From ea9accf9761d084ef0fe861edb16716d15898949 Mon Sep 17 00:00:00 2001 From: doomedraven Date: Sun, 2 Jun 2024 14:36:16 +0200 Subject: [PATCH 001/121] sync --- poetry.lock | 54 +++++--------------------------------------------- pyproject.toml | 2 +- 2 files changed, 6 insertions(+), 50 deletions(-) diff --git a/poetry.lock b/poetry.lock index 876c9e5b1d1..e4ff80ef1ad 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.8.2 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.8.3 and should not be changed by hand. [[package]] name = "alembic" @@ -1577,16 +1577,6 @@ files = [ {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-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:f698de3fd0c4e6972b92290a45bd9b1536bffe8c6759c62471efaa8acb4c37bc"}, - {file = "MarkupSafe-2.1.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:aa57bd9cf8ae831a362185ee444e15a93ecb2e344c8e52e4d721ea3ab6ef1823"}, - {file = "MarkupSafe-2.1.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ffcc3f7c66b5f5b7931a5aa68fc9cecc51e685ef90282f4a82f0f5e9b704ad11"}, - {file = "MarkupSafe-2.1.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:47d4f1c5f80fc62fdd7777d0d40a2e9dda0a05883ab11374334f6c4de38adffd"}, - {file = "MarkupSafe-2.1.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1f67c7038d560d92149c060157d623c542173016c4babc0c1913cca0564b9939"}, - {file = "MarkupSafe-2.1.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:9aad3c1755095ce347e26488214ef77e0485a3c34a50c5a5e2471dff60b9dd9c"}, - {file = "MarkupSafe-2.1.3-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:14ff806850827afd6b07a5f32bd917fb7f45b046ba40c57abdb636674a8b559c"}, - {file = "MarkupSafe-2.1.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8f9293864fe09b8149f0cc42ce56e3f0e54de883a9de90cd427f191c346eb2e1"}, - {file = "MarkupSafe-2.1.3-cp312-cp312-win32.whl", hash = "sha256:715d3562f79d540f251b99ebd6d8baa547118974341db04f5ad06d5ea3eb8007"}, - {file = "MarkupSafe-2.1.3-cp312-cp312-win_amd64.whl", hash = "sha256:1b8dd8c3fd14349433c79fa8abeb573a55fc0fdd769133baac1f5e07abf54aeb"}, {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"}, @@ -2496,8 +2486,6 @@ files = [ {file = "pydeep2-0.5.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2283893e25826b547dd1e5c71a010e86ddfd7270e2f2b8c90973c1d7984c7eb7"}, {file = "pydeep2-0.5.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f248e3161deb53d46a9368a7c164e36d83004faf2f11625d47a5cf23a6bdd2cb"}, {file = "pydeep2-0.5.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a13fca9be89a9fa8d92a4f49d7b9191eef94555f8ddf030fb2be4c8c15ad618c"}, - {file = "pydeep2-0.5.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d1cb4757db97ac15ddf034c21cd6bab984f841586b6d53984e63c9a7803b2cd4"}, - {file = "pydeep2-0.5.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7809a1d6640bdbee68f075d53229d05229e11b4711f232728dd540f68e6483a4"}, {file = "pydeep2-0.5.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0fedc1c9660cb5d0b73ad0b5f1dbffe16990e6721cbfc6454571a4b9882d0ea4"}, {file = "pydeep2-0.5.1-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7ca68f7d63e2ef510d410d20b223e8e97df41707fb50c4c526b6dd1d8698d9e6"}, {file = "pydeep2-0.5.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:199d05d8b4b7544509a2ba4802ead4b41dfe7859e0ecea9d9be9e41939f11660"}, @@ -3058,7 +3046,6 @@ files = [ {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938"}, {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d"}, {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515"}, - {file = "PyYAML-6.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:326c013efe8048858a6d312ddd31d56e468118ad4cdeda36c719bf5bb6192290"}, {file = "PyYAML-6.0.1-cp310-cp310-win32.whl", hash = "sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924"}, {file = "PyYAML-6.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d"}, {file = "PyYAML-6.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007"}, @@ -3066,16 +3053,8 @@ files = [ {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d"}, {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc"}, {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673"}, - {file = "PyYAML-6.0.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e7d73685e87afe9f3b36c799222440d6cf362062f78be1013661b00c5c6f678b"}, {file = "PyYAML-6.0.1-cp311-cp311-win32.whl", hash = "sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741"}, {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"}, - {file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"}, - {file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"}, - {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a08c6f0fe150303c1c6b71ebcd7213c2858041a7e01975da3a99aed1e7a378ef"}, - {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"}, - {file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"}, - {file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"}, - {file = "PyYAML-6.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:0d3304d8c0adc42be59c5f8a4d9e3d7379e6955ad754aa9d6ab7a398b59dd1df"}, {file = "PyYAML-6.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47"}, {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98"}, {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c"}, @@ -3092,7 +3071,6 @@ files = [ {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5"}, {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696"}, {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735"}, - {file = "PyYAML-6.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:49a183be227561de579b4a36efbb21b3eab9651dd81b1858589f796549873dd6"}, {file = "PyYAML-6.0.1-cp38-cp38-win32.whl", hash = "sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206"}, {file = "PyYAML-6.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62"}, {file = "PyYAML-6.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8"}, @@ -3100,7 +3078,6 @@ files = [ {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6"}, {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0"}, {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c"}, - {file = "PyYAML-6.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:04ac92ad1925b2cff1db0cfebffb6ffc43457495c9b3c39d3fcae417d7125dc5"}, {file = "PyYAML-6.0.1-cp39-cp39-win32.whl", hash = "sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c"}, {file = "PyYAML-6.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486"}, {file = "PyYAML-6.0.1.tar.gz", hash = "sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43"}, @@ -3188,13 +3165,13 @@ files = [ [[package]] name = "requests" -version = "2.32.0" +version = "2.32.2" description = "Python HTTP for Humans." optional = false python-versions = ">=3.8" files = [ - {file = "requests-2.32.0-py3-none-any.whl", hash = "sha256:f2c3881dddb70d056c5bd7600a4fae312b2a300e39be6a118d30b90bd27262b5"}, - {file = "requests-2.32.0.tar.gz", hash = "sha256:fa5490319474c82ef1d2c9bc459d3652e3ae4ef4c4ebdd18a21145a47ca4b6b8"}, + {file = "requests-2.32.2-py3-none-any.whl", hash = "sha256:fc06670dd0ed212426dfeb94fc1b983d917c4f9847c863f313c9dfaaffb7c23c"}, + {file = "requests-2.32.2.tar.gz", hash = "sha256:dd951ff5ecf3e3b3aa26b40703ba77495dab41da839ae72ef3c8e5d8e2433289"}, ] [package.dependencies] @@ -3558,51 +3535,30 @@ description = "Database Abstraction Library" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7" files = [ - {file = "SQLAlchemy-1.4.50-cp310-cp310-macosx_11_0_x86_64.whl", hash = "sha256:54138aa80d2dedd364f4e8220eef284c364d3270aaef621570aa2bd99902e2e8"}, {file = "SQLAlchemy-1.4.50-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d00665725063692c42badfd521d0c4392e83c6c826795d38eb88fb108e5660e5"}, {file = "SQLAlchemy-1.4.50-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:85292ff52ddf85a39367057c3d7968a12ee1fb84565331a36a8fead346f08796"}, {file = "SQLAlchemy-1.4.50-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:d0fed0f791d78e7767c2db28d34068649dfeea027b83ed18c45a423f741425cb"}, {file = "SQLAlchemy-1.4.50-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:db4db3c08ffbb18582f856545f058a7a5e4ab6f17f75795ca90b3c38ee0a8ba4"}, - {file = "SQLAlchemy-1.4.50-cp310-cp310-win32.whl", hash = "sha256:6c78e3fb4a58e900ec433b6b5f4efe1a0bf81bbb366ae7761c6e0051dd310ee3"}, - {file = "SQLAlchemy-1.4.50-cp310-cp310-win_amd64.whl", hash = "sha256:d55f7a33e8631e15af1b9e67c9387c894fedf6deb1a19f94be8731263c51d515"}, - {file = "SQLAlchemy-1.4.50-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:324b1fdd50e960a93a231abb11d7e0f227989a371e3b9bd4f1259920f15d0304"}, {file = "SQLAlchemy-1.4.50-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:14b0cacdc8a4759a1e1bd47dc3ee3f5db997129eb091330beda1da5a0e9e5bd7"}, {file = "SQLAlchemy-1.4.50-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1fb9cb60e0f33040e4f4681e6658a7eb03b5cb4643284172f91410d8c493dace"}, - {file = "SQLAlchemy-1.4.50-cp311-cp311-win32.whl", hash = "sha256:8bdab03ff34fc91bfab005e96f672ae207d87e0ac7ee716d74e87e7046079d8b"}, - {file = "SQLAlchemy-1.4.50-cp311-cp311-win_amd64.whl", hash = "sha256:52e01d60b06f03b0a5fc303c8aada405729cbc91a56a64cead8cb7c0b9b13c1a"}, - {file = "SQLAlchemy-1.4.50-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:77fde9bf74f4659864c8e26ac08add8b084e479b9a18388e7db377afc391f926"}, {file = "SQLAlchemy-1.4.50-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c4cb501d585aa74a0f86d0ea6263b9c5e1d1463f8f9071392477fd401bd3c7cc"}, {file = "SQLAlchemy-1.4.50-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8a7a66297e46f85a04d68981917c75723e377d2e0599d15fbe7a56abed5e2d75"}, - {file = "SQLAlchemy-1.4.50-cp312-cp312-win32.whl", hash = "sha256:e86c920b7d362cfa078c8b40e7765cbc34efb44c1007d7557920be9ddf138ec7"}, - {file = "SQLAlchemy-1.4.50-cp312-cp312-win_amd64.whl", hash = "sha256:6b3df20fbbcbcd1c1d43f49ccf3eefb370499088ca251ded632b8cbaee1d497d"}, - {file = "SQLAlchemy-1.4.50-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:fb9adc4c6752d62c6078c107d23327aa3023ef737938d0135ece8ffb67d07030"}, {file = "SQLAlchemy-1.4.50-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c1db0221cb26d66294f4ca18c533e427211673ab86c1fbaca8d6d9ff78654293"}, {file = "SQLAlchemy-1.4.50-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0b7dbe6369677a2bea68fe9812c6e4bbca06ebfa4b5cde257b2b0bf208709131"}, {file = "SQLAlchemy-1.4.50-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:a9bddb60566dc45c57fd0a5e14dd2d9e5f106d2241e0a2dc0c1da144f9444516"}, {file = "SQLAlchemy-1.4.50-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:82dd4131d88395df7c318eeeef367ec768c2a6fe5bd69423f7720c4edb79473c"}, - {file = "SQLAlchemy-1.4.50-cp36-cp36m-win32.whl", hash = "sha256:1b9c4359d3198f341480e57494471201e736de459452caaacf6faa1aca852bd8"}, - {file = "SQLAlchemy-1.4.50-cp36-cp36m-win_amd64.whl", hash = "sha256:35e4520f7c33c77f2636a1e860e4f8cafaac84b0b44abe5de4c6c8890b6aaa6d"}, - {file = "SQLAlchemy-1.4.50-cp37-cp37m-macosx_11_0_x86_64.whl", hash = "sha256:f5b1fb2943d13aba17795a770d22a2ec2214fc65cff46c487790192dda3a3ee7"}, {file = "SQLAlchemy-1.4.50-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:273505fcad22e58cc67329cefab2e436006fc68e3c5423056ee0513e6523268a"}, {file = "SQLAlchemy-1.4.50-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a3257a6e09626d32b28a0c5b4f1a97bced585e319cfa90b417f9ab0f6145c33c"}, {file = "SQLAlchemy-1.4.50-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:d69738d582e3a24125f0c246ed8d712b03bd21e148268421e4a4d09c34f521a5"}, {file = "SQLAlchemy-1.4.50-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:34e1c5d9cd3e6bf3d1ce56971c62a40c06bfc02861728f368dcfec8aeedb2814"}, - {file = "SQLAlchemy-1.4.50-cp37-cp37m-win32.whl", hash = "sha256:7b4396452273aedda447e5aebe68077aa7516abf3b3f48408793e771d696f397"}, - {file = "SQLAlchemy-1.4.50-cp37-cp37m-win_amd64.whl", hash = "sha256:752f9df3dddbacb5f42d8405b2d5885675a93501eb5f86b88f2e47a839cf6337"}, - {file = "SQLAlchemy-1.4.50-cp38-cp38-macosx_11_0_x86_64.whl", hash = "sha256:35c7ed095a4b17dbc8813a2bfb38b5998318439da8e6db10a804df855e3a9e3a"}, {file = "SQLAlchemy-1.4.50-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f1fcee5a2c859eecb4ed179edac5ffbc7c84ab09a5420219078ccc6edda45436"}, {file = "SQLAlchemy-1.4.50-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fbaf6643a604aa17e7a7afd74f665f9db882df5c297bdd86c38368f2c471f37d"}, {file = "SQLAlchemy-1.4.50-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:2e70e0673d7d12fa6cd363453a0d22dac0d9978500aa6b46aa96e22690a55eab"}, {file = "SQLAlchemy-1.4.50-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8b881ac07d15fb3e4f68c5a67aa5cdaf9eb8f09eb5545aaf4b0a5f5f4659be18"}, - {file = "SQLAlchemy-1.4.50-cp38-cp38-win32.whl", hash = "sha256:8a219688297ee5e887a93ce4679c87a60da4a5ce62b7cb4ee03d47e9e767f558"}, - {file = "SQLAlchemy-1.4.50-cp38-cp38-win_amd64.whl", hash = "sha256:a648770db002452703b729bdcf7d194e904aa4092b9a4d6ab185b48d13252f63"}, - {file = "SQLAlchemy-1.4.50-cp39-cp39-macosx_11_0_x86_64.whl", hash = "sha256:4be4da121d297ce81e1ba745a0a0521c6cf8704634d7b520e350dce5964c71ac"}, {file = "SQLAlchemy-1.4.50-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3f6997da81114daef9203d30aabfa6b218a577fc2bd797c795c9c88c9eb78d49"}, {file = "SQLAlchemy-1.4.50-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bdb77e1789e7596b77fd48d99ec1d2108c3349abd20227eea0d48d3f8cf398d9"}, {file = "SQLAlchemy-1.4.50-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:128a948bd40780667114b0297e2cc6d657b71effa942e0a368d8cc24293febb3"}, {file = "SQLAlchemy-1.4.50-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f2d526aeea1bd6a442abc7c9b4b00386fd70253b80d54a0930c0a216230a35be"}, - {file = "SQLAlchemy-1.4.50-cp39-cp39-win32.whl", hash = "sha256:a7c9b9dca64036008962dd6b0d9fdab2dfdbf96c82f74dbd5d86006d8d24a30f"}, - {file = "SQLAlchemy-1.4.50-cp39-cp39-win_amd64.whl", hash = "sha256:df200762efbd672f7621b253721644642ff04a6ff957236e0e2fe56d9ca34d2c"}, {file = "SQLAlchemy-1.4.50.tar.gz", hash = "sha256:3b97ddf509fc21e10b09403b5219b06c5b558b27fc2453150274fa4e70707dbf"}, ] @@ -4345,4 +4301,4 @@ testing = ["coverage (>=5.0.3)", "zope.event", "zope.testing"] [metadata] lock-version = "2.0" python-versions = "^3.10" -content-hash = "ff5ad5722e3199a1b1862caea8ffa34f2411e8b3fb29f4a2c13c9aa4a98e5241" +content-hash = "943f51a6233c58160869c8d5ea4ceac8ff9b42d314097be39e457dc7eee3ae99" diff --git a/pyproject.toml b/pyproject.toml index 895899b0a5f..1482ad56a6c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -13,7 +13,7 @@ greenlet = "3.0.0rc3" Pebble = "4.6.3" # pymisp = "2.4.144" cryptography = "42.0.4" -requests = {version = "2.32.0", extras = ["security", "socks"]} +requests = {version = "2.32.2", extras = ["security", "socks"]} pyOpenSSL = "24.0.0" pefile = "*" dnfile="0.14.1" From 6ef4041fcc02d66f4e3f2efc4e55e578e82b069b Mon Sep 17 00:00:00 2001 From: GitHub Actions Date: Sun, 2 Jun 2024 12:36:49 +0000 Subject: [PATCH 002/121] ci: Update requirements.txt --- requirements.txt | 58 ++++++------------------------------------------ 1 file changed, 7 insertions(+), 51 deletions(-) diff --git a/requirements.txt b/requirements.txt index 05ebeffbd67..ca9c42bc2d7 100644 --- a/requirements.txt +++ b/requirements.txt @@ -538,11 +538,8 @@ markupsafe==2.1.3 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:0a4e4a1aff6c7ac4cd55792abf96c915634c2b97e3cc1c7129578aa68ebd754e \ --hash=sha256:10bbfe99883db80bdbaff2dcf681dfc6533a614f700da1287707e8a5d78a8431 \ --hash=sha256:134da1eca9ec0ae528110ccc9e48041e0828d79f24121a1a146161103c76e686 \ - --hash=sha256:14ff806850827afd6b07a5f32bd917fb7f45b046ba40c57abdb636674a8b559c \ --hash=sha256:1577735524cdad32f9f694208aa75e422adba74f1baee7551620e43a3141f559 \ --hash=sha256:1b40069d487e7edb2676d3fbdb2b0829ffa2cd63a2ec26c4938b2d34391b4ecc \ - --hash=sha256:1b8dd8c3fd14349433c79fa8abeb573a55fc0fdd769133baac1f5e07abf54aeb \ - --hash=sha256:1f67c7038d560d92149c060157d623c542173016c4babc0c1913cca0564b9939 \ --hash=sha256:282c2cb35b5b673bbcadb33a585408104df04f14b2d9b01d4c345a3b92861c2c \ --hash=sha256:2c1b19b3aaacc6e57b7e25710ff571c24d6c3613a45e905b1fde04d691b98ee0 \ --hash=sha256:2ef12179d3a291be237280175b542c07a36e7f60718296278d8593d21ca937d4 \ @@ -550,7 +547,6 @@ markupsafe==2.1.3 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:3c0fae6c3be832a0a0473ac912810b2877c8cb9d76ca48de1ed31e1c68386575 \ --hash=sha256:3fd4abcb888d15a94f32b75d8fd18ee162ca0c064f35b11134be77050296d6ba \ --hash=sha256:42de32b22b6b804f42c5d98be4f7e5e977ecdd9ee9b660fda1a3edf03b11792d \ - --hash=sha256:47d4f1c5f80fc62fdd7777d0d40a2e9dda0a05883ab11374334f6c4de38adffd \ --hash=sha256:504b320cd4b7eff6f968eddf81127112db685e81f7e36e75f9f84f0df46041c3 \ --hash=sha256:525808b8019e36eb524b8c68acdd63a37e75714eac50e988180b169d64480a00 \ --hash=sha256:56d9f2ecac662ca1611d183feb03a3fa4406469dafe241673d521dd5ae92a155 \ @@ -559,7 +555,6 @@ markupsafe==2.1.3 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:68e78619a61ecf91e76aa3e6e8e33fc4894a2bebe93410754bd28fce0a8a4f9f \ --hash=sha256:69c0f17e9f5a7afdf2cc9fb2d1ce6aabdb3bafb7f38017c0b77862bcec2bbad8 \ --hash=sha256:6b2b56950d93e41f33b4223ead100ea0fe11f8e6ee5f641eb753ce4b77a7042b \ - --hash=sha256:715d3562f79d540f251b99ebd6d8baa547118974341db04f5ad06d5ea3eb8007 \ --hash=sha256:787003c0ddb00500e49a10f2844fac87aa6ce977b90b0feaaf9de23c22508b24 \ --hash=sha256:7ef3cb2ebbf91e330e3bb937efada0edd9003683db6b57bb108c4001f37a02ea \ --hash=sha256:8023faf4e01efadfa183e863fefde0046de576c6f14659e8782065bcece22198 \ @@ -567,12 +562,9 @@ markupsafe==2.1.3 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:8afafd99945ead6e075b973fefa56379c5b5c53fd8937dad92c662da5d8fd5ee \ --hash=sha256:8c41976a29d078bb235fea9b2ecd3da465df42a562910f9022f1a03107bd02be \ --hash=sha256:8e254ae696c88d98da6555f5ace2279cf7cd5b3f52be2b5cf97feafe883b58d2 \ - --hash=sha256:8f9293864fe09b8149f0cc42ce56e3f0e54de883a9de90cd427f191c346eb2e1 \ --hash=sha256:9402b03f1a1b4dc4c19845e5c749e3ab82d5078d16a2a4c2cd2df62d57bb0707 \ --hash=sha256:962f82a3086483f5e5f64dbad880d31038b698494799b097bc59c2edf392fce6 \ - --hash=sha256:9aad3c1755095ce347e26488214ef77e0485a3c34a50c5a5e2471dff60b9dd9c \ --hash=sha256:9dcdfd0eaf283af041973bff14a2e143b8bd64e069f4c383416ecd79a81aab58 \ - --hash=sha256:aa57bd9cf8ae831a362185ee444e15a93ecb2e344c8e52e4d721ea3ab6ef1823 \ --hash=sha256:aa7bd130efab1c280bed0f45501b7c8795f9fdbeb02e965371bbef3523627779 \ --hash=sha256:ab4a0df41e7c16a1392727727e7998a467472d0ad65f3ad5e6e765015df08636 \ --hash=sha256:ad9e82fb8f09ade1c3e1b996a6337afac2b8b9e365f926f5a61aacc71adc5b3c \ @@ -591,9 +583,7 @@ markupsafe==2.1.3 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:df0be2b576a7abbf737b1575f048c23fb1d769f267ec4358296f31c2479db8f9 \ --hash=sha256:e09031c87a1e51556fdcb46e5bd4f59dfb743061cf93c4d6831bf894f125eb57 \ --hash=sha256:e4dd52d80b8c83fdce44e12478ad2e85c64ea965e75d66dbeafb0a3e77308fcc \ - --hash=sha256:f698de3fd0c4e6972b92290a45bd9b1536bffe8c6759c62471efaa8acb4c37bc \ - --hash=sha256:fec21693218efe39aa7f8599346e90c705afa52c5b31ae019b2e57e8f6542bb2 \ - --hash=sha256:ffcc3f7c66b5f5b7931a5aa68fc9cecc51e685ef90282f4a82f0f5e9b704ad11 + --hash=sha256:fec21693218efe39aa7f8599346e90c705afa52c5b31ae019b2e57e8f6542bb2 maxminddb==2.5.1 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:0702da59b9670a72761b65cb1a52bc3032d8f6799bdab641cb8350ad5740580b \ --hash=sha256:0a21abd85e10e5e0f60244b49c3db17e7e48befd4972e62a62833d91e2acbb49 \ @@ -1121,13 +1111,11 @@ pydeep2==0.5.1 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:2283893e25826b547dd1e5c71a010e86ddfd7270e2f2b8c90973c1d7984c7eb7 \ --hash=sha256:44ce447e3253a69d3393f3cc53e3a87a48fe3ff9861793736a7bc218a1b95d77 \ --hash=sha256:4bf00de2fe1918e4d698fe8195a5c0a3a0c3050a2e3e15583748cfd20b427153 \ - --hash=sha256:7809a1d6640bdbee68f075d53229d05229e11b4711f232728dd540f68e6483a4 \ --hash=sha256:7ca68f7d63e2ef510d410d20b223e8e97df41707fb50c4c526b6dd1d8698d9e6 \ --hash=sha256:a13fca9be89a9fa8d92a4f49d7b9191eef94555f8ddf030fb2be4c8c15ad618c \ --hash=sha256:add24d7aa0386b285fd3e99632719714efabeb13d7b03a015b7c64d1f588f815 \ --hash=sha256:c2063cbb053e5ce684cc45fff3e72c063b26aa85e41e6435cab0c658ad9e3e1e \ --hash=sha256:c65dc910d782fa2bc97e1b28a78d77c4bada037d14b63e3e75a1fa5918d642c5 \ - --hash=sha256:d1cb4757db97ac15ddf034c21cd6bab984f841586b6d53984e63c9a7803b2cd4 \ --hash=sha256:e14b310b820d895a7354be7fd025de874892df249cbfb3ad8a524459e1511fd8 \ --hash=sha256:ef00ca5681a2c4ad5dc744db5f8ae5406d3f13121b38d84cc58dfb8fce4c3dc2 \ --hash=sha256:f248e3161deb53d46a9368a7c164e36d83004faf2f11625d47a5cf23a6bdd2cb @@ -1308,9 +1296,7 @@ pytz==2021.1 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:83a4a90894bf38e243cf052c8b58f381bfe9a7a483f6a9cab140bc7f702ac4da \ --hash=sha256:eb10ce3e7736052ed3623d49975ce333bcd712c7bb19a58b9e2089d4057d0798 pyyaml==6.0.1 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:04ac92ad1925b2cff1db0cfebffb6ffc43457495c9b3c39d3fcae417d7125dc5 \ --hash=sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc \ - --hash=sha256:0d3304d8c0adc42be59c5f8a4d9e3d7379e6955ad754aa9d6ab7a398b59dd1df \ --hash=sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741 \ --hash=sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206 \ --hash=sha256:18aeb1bf9a78867dc38b259769503436b7c72f7a1f1f4c93ff9a17de54319b27 \ @@ -1318,10 +1304,7 @@ pyyaml==6.0.1 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62 \ --hash=sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98 \ --hash=sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696 \ - --hash=sha256:326c013efe8048858a6d312ddd31d56e468118ad4cdeda36c719bf5bb6192290 \ - --hash=sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9 \ --hash=sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d \ - --hash=sha256:49a183be227561de579b4a36efbb21b3eab9651dd81b1858589f796549873dd6 \ --hash=sha256:4fb147e7a67ef577a588a0e2c17b6db51dda102c71de36f8549b6816a96e1867 \ --hash=sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47 \ --hash=sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486 \ @@ -1329,15 +1312,11 @@ pyyaml==6.0.1 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:596106435fa6ad000c2991a98fa58eeb8656ef2325d7e158344fb33864ed87e3 \ --hash=sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007 \ --hash=sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938 \ - --hash=sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0 \ --hash=sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c \ --hash=sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735 \ --hash=sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d \ - --hash=sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28 \ - --hash=sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4 \ --hash=sha256:9046c58c4395dff28dd494285c82ba00b546adfc7ef001486fbf0324bc174fba \ --hash=sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8 \ - --hash=sha256:a08c6f0fe150303c1c6b71ebcd7213c2858041a7e01975da3a99aed1e7a378ef \ --hash=sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5 \ --hash=sha256:afd7e57eddb1a54f0f1a974bc4391af8bcce0b444685d936840f125cf046d5bd \ --hash=sha256:b1275ad35a5d18c62a7220633c913e1b42d44b46ee12554e5fd39c70a243d6a3 \ @@ -1350,9 +1329,7 @@ pyyaml==6.0.1 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43 \ --hash=sha256:c8098ddcc2a85b61647b2590f825f3db38891662cfc2fc776415143f599bb859 \ --hash=sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673 \ - --hash=sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54 \ --hash=sha256:d858aa552c999bc8a8d57426ed01e40bef403cd8ccdd0fc5f6f04a00414cac2a \ - --hash=sha256:e7d73685e87afe9f3b36c799222440d6cf362062f78be1013661b00c5c6f678b \ --hash=sha256:f003ed9ad21d6a4713f0a9b5a7a0a79e08dd0f221aff4525a2be4c346ee60aab \ --hash=sha256:f22ac1c3cac4dbc50079e965eba2c1058622631e526bd9afd45fedd49ba781fa \ --hash=sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c \ @@ -1426,12 +1403,12 @@ requests-file==1.5.1 ; python_version >= "3.10" and python_version < "4.0" \ requests-oauthlib==1.3.1 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:2577c501a2fb8d05a304c09d090d6e47c306fef15809d102b327cf8364bddab5 \ --hash=sha256:75beac4a47881eeb94d5ea5d6ad31ef88856affe2332b9aafb52c6452ccf0d7a -requests==2.32.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:f2c3881dddb70d056c5bd7600a4fae312b2a300e39be6a118d30b90bd27262b5 \ - --hash=sha256:fa5490319474c82ef1d2c9bc459d3652e3ae4ef4c4ebdd18a21145a47ca4b6b8 -requests[security,socks]==2.32.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:f2c3881dddb70d056c5bd7600a4fae312b2a300e39be6a118d30b90bd27262b5 \ - --hash=sha256:fa5490319474c82ef1d2c9bc459d3652e3ae4ef4c4ebdd18a21145a47ca4b6b8 +requests==2.32.2 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:dd951ff5ecf3e3b3aa26b40703ba77495dab41da839ae72ef3c8e5d8e2433289 \ + --hash=sha256:fc06670dd0ed212426dfeb94fc1b983d917c4f9847c863f313c9dfaaffb7c23c +requests[security,socks]==2.32.2 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:dd951ff5ecf3e3b3aa26b40703ba77495dab41da839ae72ef3c8e5d8e2433289 \ + --hash=sha256:fc06670dd0ed212426dfeb94fc1b983d917c4f9847c863f313c9dfaaffb7c23c ruamel-yaml-clib==0.2.7 ; platform_python_implementation == "CPython" and python_version < "3.13" and python_version >= "3.10" \ --hash=sha256:045e0626baf1c52e5527bd5db361bc83180faaba2ff586e763d3d5982a876a9e \ --hash=sha256:15910ef4f3e537eea7fe45f8a5d19997479940d9196f357152a09031c5be59f3 \ @@ -1594,48 +1571,27 @@ sqlalchemy==1.4.50 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:0b7dbe6369677a2bea68fe9812c6e4bbca06ebfa4b5cde257b2b0bf208709131 \ --hash=sha256:128a948bd40780667114b0297e2cc6d657b71effa942e0a368d8cc24293febb3 \ --hash=sha256:14b0cacdc8a4759a1e1bd47dc3ee3f5db997129eb091330beda1da5a0e9e5bd7 \ - --hash=sha256:1b9c4359d3198f341480e57494471201e736de459452caaacf6faa1aca852bd8 \ --hash=sha256:1fb9cb60e0f33040e4f4681e6658a7eb03b5cb4643284172f91410d8c493dace \ --hash=sha256:273505fcad22e58cc67329cefab2e436006fc68e3c5423056ee0513e6523268a \ --hash=sha256:2e70e0673d7d12fa6cd363453a0d22dac0d9978500aa6b46aa96e22690a55eab \ - --hash=sha256:324b1fdd50e960a93a231abb11d7e0f227989a371e3b9bd4f1259920f15d0304 \ --hash=sha256:34e1c5d9cd3e6bf3d1ce56971c62a40c06bfc02861728f368dcfec8aeedb2814 \ - --hash=sha256:35c7ed095a4b17dbc8813a2bfb38b5998318439da8e6db10a804df855e3a9e3a \ - --hash=sha256:35e4520f7c33c77f2636a1e860e4f8cafaac84b0b44abe5de4c6c8890b6aaa6d \ --hash=sha256:3b97ddf509fc21e10b09403b5219b06c5b558b27fc2453150274fa4e70707dbf \ --hash=sha256:3f6997da81114daef9203d30aabfa6b218a577fc2bd797c795c9c88c9eb78d49 \ - --hash=sha256:4be4da121d297ce81e1ba745a0a0521c6cf8704634d7b520e350dce5964c71ac \ - --hash=sha256:52e01d60b06f03b0a5fc303c8aada405729cbc91a56a64cead8cb7c0b9b13c1a \ - --hash=sha256:54138aa80d2dedd364f4e8220eef284c364d3270aaef621570aa2bd99902e2e8 \ - --hash=sha256:6b3df20fbbcbcd1c1d43f49ccf3eefb370499088ca251ded632b8cbaee1d497d \ - --hash=sha256:6c78e3fb4a58e900ec433b6b5f4efe1a0bf81bbb366ae7761c6e0051dd310ee3 \ - --hash=sha256:752f9df3dddbacb5f42d8405b2d5885675a93501eb5f86b88f2e47a839cf6337 \ - --hash=sha256:77fde9bf74f4659864c8e26ac08add8b084e479b9a18388e7db377afc391f926 \ - --hash=sha256:7b4396452273aedda447e5aebe68077aa7516abf3b3f48408793e771d696f397 \ --hash=sha256:82dd4131d88395df7c318eeeef367ec768c2a6fe5bd69423f7720c4edb79473c \ --hash=sha256:85292ff52ddf85a39367057c3d7968a12ee1fb84565331a36a8fead346f08796 \ - --hash=sha256:8a219688297ee5e887a93ce4679c87a60da4a5ce62b7cb4ee03d47e9e767f558 \ --hash=sha256:8a7a66297e46f85a04d68981917c75723e377d2e0599d15fbe7a56abed5e2d75 \ --hash=sha256:8b881ac07d15fb3e4f68c5a67aa5cdaf9eb8f09eb5545aaf4b0a5f5f4659be18 \ - --hash=sha256:8bdab03ff34fc91bfab005e96f672ae207d87e0ac7ee716d74e87e7046079d8b \ --hash=sha256:a3257a6e09626d32b28a0c5b4f1a97bced585e319cfa90b417f9ab0f6145c33c \ - --hash=sha256:a648770db002452703b729bdcf7d194e904aa4092b9a4d6ab185b48d13252f63 \ - --hash=sha256:a7c9b9dca64036008962dd6b0d9fdab2dfdbf96c82f74dbd5d86006d8d24a30f \ --hash=sha256:a9bddb60566dc45c57fd0a5e14dd2d9e5f106d2241e0a2dc0c1da144f9444516 \ --hash=sha256:bdb77e1789e7596b77fd48d99ec1d2108c3349abd20227eea0d48d3f8cf398d9 \ --hash=sha256:c1db0221cb26d66294f4ca18c533e427211673ab86c1fbaca8d6d9ff78654293 \ --hash=sha256:c4cb501d585aa74a0f86d0ea6263b9c5e1d1463f8f9071392477fd401bd3c7cc \ --hash=sha256:d00665725063692c42badfd521d0c4392e83c6c826795d38eb88fb108e5660e5 \ --hash=sha256:d0fed0f791d78e7767c2db28d34068649dfeea027b83ed18c45a423f741425cb \ - --hash=sha256:d55f7a33e8631e15af1b9e67c9387c894fedf6deb1a19f94be8731263c51d515 \ --hash=sha256:d69738d582e3a24125f0c246ed8d712b03bd21e148268421e4a4d09c34f521a5 \ --hash=sha256:db4db3c08ffbb18582f856545f058a7a5e4ab6f17f75795ca90b3c38ee0a8ba4 \ - --hash=sha256:df200762efbd672f7621b253721644642ff04a6ff957236e0e2fe56d9ca34d2c \ - --hash=sha256:e86c920b7d362cfa078c8b40e7765cbc34efb44c1007d7557920be9ddf138ec7 \ --hash=sha256:f1fcee5a2c859eecb4ed179edac5ffbc7c84ab09a5420219078ccc6edda45436 \ --hash=sha256:f2d526aeea1bd6a442abc7c9b4b00386fd70253b80d54a0930c0a216230a35be \ - --hash=sha256:f5b1fb2943d13aba17795a770d22a2ec2214fc65cff46c487790192dda3a3ee7 \ - --hash=sha256:fb9adc4c6752d62c6078c107d23327aa3023ef737938d0135ece8ffb67d07030 \ --hash=sha256:fbaf6643a604aa17e7a7afd74f665f9db882df5c297bdd86c38368f2c471f37d sqlparse==0.5.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:714d0a4932c059d16189f58ef5411ec2287a4360f17cdd0edd2d09d4c5087c93 \ From a23affff1ecd276e33870fcde9948671ab7da4ba Mon Sep 17 00:00:00 2001 From: piolug93 Date: Sun, 2 Jun 2024 14:40:49 +0200 Subject: [PATCH 003/121] Feature to ability monitor traffic between cape result server and sandbox. (#2116) * Feature for use VRF to change behavior of handling traffic by loopback. Now traffic will be go to dirty line. --- conf/default/routing.conf.default | 8 + lib/cuckoo/core/scheduler.py | 981 ++++++++++++++++++++---------- lib/cuckoo/core/startup.py | 17 +- pyproject.toml | 2 +- utils/rooter.py | 126 +++- 5 files changed, 790 insertions(+), 344 deletions(-) diff --git a/conf/default/routing.conf.default b/conf/default/routing.conf.default index 7b29d6d4852..fd4e281efad 100644 --- a/conf/default/routing.conf.default +++ b/conf/default/routing.conf.default @@ -22,6 +22,14 @@ route = none # (For example, to route all VMs through eth0 by default: "internet = eth0"). internet = none +# When set to no masquerade rule has been not generated. +nat = yes + +# When property nat set to yes. That property not used. +# When property nat set to no and no_local_routing to yes, a vrf configuration +# will be generated and local traffic will go through by internet interface (dirty_line). +no_local_routing = yes + # Routing table name/id for "dirty line" interface. If "dirty line" is # also default gateway in the system you can leave "main" value. Otherwise add # new routing table by adding " " line to /etc/iproute2/rt_tables diff --git a/lib/cuckoo/core/scheduler.py b/lib/cuckoo/core/scheduler.py index 4fbdf43c74f..3111f2563ed 100644 --- a/lib/cuckoo/core/scheduler.py +++ b/lib/cuckoo/core/scheduler.py @@ -1,375 +1,708 @@ -# Copyright (C) 2010-2015 Cuckoo Foundation. -# This file is part of Cuckoo Sandbox - http://www.cuckoosandbox.org -# See the file 'docs/LICENSE' for copying permission. - import contextlib -import enum +import functools import logging import os import queue -import signal +import shutil import threading -import time -from collections import defaultdict -from typing import DefaultDict, List, Optional, Tuple +from typing import Any, Callable, Generator, MutableMapping, Optional, Tuple from lib.cuckoo.common.cleaners_utils import free_space_monitor from lib.cuckoo.common.config import Config from lib.cuckoo.common.constants import CUCKOO_ROOT -from lib.cuckoo.common.exceptions import CuckooUnserviceableTaskError -from lib.cuckoo.common.utils import CATEGORIES_NEEDING_VM, load_categories -from lib.cuckoo.core.analysis_manager import AnalysisManager -from lib.cuckoo.core.database import TASK_FAILED_ANALYSIS, TASK_PENDING, Database, Machine, Task, _Database +from lib.cuckoo.common.exceptions import ( + CuckooCriticalError, + CuckooGuestCriticalTimeout, + CuckooGuestError, + CuckooMachineError, + CuckooOperationalError, +) +from lib.cuckoo.common.integrations.parse_pe import PortableExecutable +from lib.cuckoo.common.objects import File +from lib.cuckoo.common.path_utils import path_delete, path_exists, path_mkdir +from lib.cuckoo.common.utils import convert_to_printable, create_folder, get_memdump_path +from lib.cuckoo.core.database import TASK_COMPLETED, TASK_PENDING, TASK_RUNNING, Database, Guest, Machine, Task, _Database +from lib.cuckoo.core.guest import GuestManager from lib.cuckoo.core.machinery_manager import MachineryManager +from lib.cuckoo.core.plugins import RunAuxiliary +from lib.cuckoo.core.resultserver import ResultServer +from lib.cuckoo.core.rooter import _load_socks5_operational, rooter, vpns log = logging.getLogger(__name__) +# os.listdir('/sys/class/net/') +HAVE_NETWORKIFACES = False +try: + import psutil + + network_interfaces = list(psutil.net_if_addrs().keys()) + HAVE_NETWORKIFACES = True +except ImportError: + print("Missed dependency: pip3 install psutil") + +latest_symlink_lock = threading.Lock() -class LoopState(enum.IntEnum): - """Enum that represents the state of the main scheduler loop.""" - RUNNING = 1 - PAUSED = 2 - STOPPING = 3 - INACTIVE = 4 +class CuckooDeadMachine(Exception): + """Exception thrown when a machine turns dead. + + When this exception has been thrown, the analysis task will start again, + and will try to use another machine, when available. + """ + def __init__(self, machine_name: str): + super().__init__() + self.machine_name = machine_name -class SchedulerCycleDelay(enum.IntEnum): - SUCCESS = 0 - NO_PENDING_TASKS = 1 - MAX_MACHINES_RUNNING = 1 - SCHEDULER_PAUSED = 5 - FAILURE = 5 - LOW_DISK_SPACE = 30 + def __str__(self) -> str: + return f"{self.machine_name} is dead!" -class Scheduler: - """Tasks Scheduler. +def main_thread_only(func): + # Since most methods of the AnalysisManager class will be called within a child + # thread, let's decorate ones that must only be called from the main thread so + # that it's easy to differentiate between them. + @functools.wraps(func) + def inner(*args, **kwargs): + if threading.current_thread() is not threading.main_thread(): + raise AssertionError(f"{func.__name__} must only be called from the main thread") + return func(*args, **kwargs) - This class is responsible for the main execution loop of the tool. It - prepares the analysis machines and keep waiting and loading for new - analysis tasks. - Whenever a new task is available, it launches AnalysisManager which will - take care of running the full analysis process and operating with the - assigned analysis machine. + return inner + + +class AnalysisLogger(logging.LoggerAdapter): + """This class will be used by AnalysisManager so that all of its log entries + will include the task ID, without having to explicitly include it in the log message. """ - def __init__(self, maxcount=0): - self.loop_state = LoopState.INACTIVE - self.cfg = Config() - self.db: _Database = Database() - self.max_analysis_count: int = maxcount or self.cfg.cuckoo.max_analysis_count - self.analysis_threads_lock = threading.Lock() - self.total_analysis_count: int = 0 - self.analysis_threads: List[AnalysisManager] = [] - self.analyzing_categories, categories_need_VM = load_categories() - self.machinery_manager = MachineryManager() if categories_need_VM else None - log.info("Creating scheduler with max_analysis_count=%s", self.max_analysis_count or "unlimited") - - @property - def active_analysis_count(self) -> int: - with self.analysis_threads_lock: - return len(self.analysis_threads) - - def analysis_finished(self, analysis_manager: AnalysisManager): - with self.analysis_threads_lock: - try: - self.analysis_threads.remove(analysis_manager) - except ValueError: - pass - - def do_main_loop_work(self, error_queue: queue.Queue) -> SchedulerCycleDelay: - """Return the number of seconds to sleep after returning.""" - if self.loop_state == LoopState.STOPPING: - # This blocks the main loop until the analyses are finished. - self.wait_for_running_analyses_to_finish() - self.loop_state = LoopState.INACTIVE - return SchedulerCycleDelay.SUCCESS - - if self.loop_state == LoopState.PAUSED: - log.debug("scheduler is paused, send '%s' to process %d to resume", signal.SIGUSR2, os.getpid()) - return SchedulerCycleDelay.SCHEDULER_PAUSED - - if 0 < self.max_analysis_count <= self.total_analysis_count: - log.info("Maximum analysis count has been reached, shutting down.") - self.stop() - return SchedulerCycleDelay.SUCCESS - - if self.is_short_on_disk_space(): - return SchedulerCycleDelay.LOW_DISK_SPACE - - analysis_manager: Optional[AnalysisManager] = None - with self.db.session.begin(): - max_machines_reached = False - if self.machinery_manager and self.machinery_manager.running_machines_max_reached(): - if not self.cfg.cuckoo.allow_static: - return SchedulerCycleDelay.MAX_MACHINES_RUNNING - max_machines_reached = True + def process(self, msg: str, kwargs: MutableMapping[str, Any]) -> Tuple[str, MutableMapping[str, Any]]: + task_id: Optional[int] = self.extra.get("task_id") if self.extra is not None else None + if task_id is not None: + msg = f"Task #{task_id}: {msg}" + return msg, kwargs - try: - task, machine = self.find_next_serviceable_task(max_machines_reached) - except Exception: - log.exception("Failed to find next serviceable task") - # Explicitly call rollback since we're not re-raising the exception and letting the - # begin() context manager handle rolling back the transaction. - self.db.session.rollback() - return SchedulerCycleDelay.FAILURE - - if task is None: - # There are no pending tasks so try again in 1 second. - return SchedulerCycleDelay.NO_PENDING_TASKS - - log.info("Task #%s: Processing task", task.id) - self.total_analysis_count += 1 - analysis_manager = AnalysisManager( - task, - machine=machine, - machinery_manager=self.machinery_manager, - error_queue=error_queue, - done_callback=self.analysis_finished, + +class AnalysisManager(threading.Thread): + """Analysis Manager. + + This class handles the full analysis process for a given task. It takes + care of selecting the analysis machine, preparing the configuration and + interacting with the guest agent and analyzer components to launch and + complete the analysis and store, process and report its results. + """ + + def __init__( + self, + task: Task, + *, + machine: Optional[Machine] = None, + machinery_manager: Optional[MachineryManager] = None, + error_queue: Optional[queue.Queue] = None, + done_callback: Optional[Callable[["AnalysisManager"], None]] = None, + ): + """@param task: task object containing the details for the analysis.""" + super().__init__(name=f"task-{task.id}", daemon=True) + self.db: _Database = Database() + self.task = task + self.log = AnalysisLogger(log, {"task_id": self.task.id}) + self.machine = machine + self.machinery_manager = machinery_manager + self.error_queue = error_queue + self.done_callback = done_callback + self.guest: Optional[Guest] = None + self.cfg = Config() + self.aux_cfg = Config("auxiliary") + self.storage = os.path.join(CUCKOO_ROOT, "storage", "analyses", str(self.task.id)) + self.screenshot_path = os.path.join(self.storage, "shots") + self.num_screenshots = 0 + self.binary = "" + self.interface = None + self.rt_table = None + self.route = None + self.rooter_response = "" + self.reject_segments = None + self.reject_hostports = None + + @main_thread_only + def prepare_task_and_machine_to_start(self) -> None: + """If the task doesn't use a machine, just set its state to running. + Otherwise, update the task and machine in the database so that the + task is running, the machine is locked and assigned to the task, and + create a Guest row for the analysis. + """ + self.db.set_task_status(self.task, TASK_RUNNING) + if self.machine and self.machinery_manager: + self.db.assign_machine_to_task(self.task, self.machine) + self.db.lock_machine(self.machine) + self.guest = self.db.create_guest( + self.machine, + self.machinery_manager.machinery.__class__.__name__, + self.task, ) - analysis_manager.prepare_task_and_machine_to_start() - self.db.session.expunge_all() - with self.analysis_threads_lock: - self.analysis_threads.append(analysis_manager) - analysis_manager.start() + def init_storage(self): + """Initialize analysis storage folder.""" + # If the analysis storage folder already exists, we need to abort the + # analysis or previous results will be overwritten and lost. + if path_exists(self.storage): + self.log.error("Analysis results folder already exists at path '%s', analysis aborted", self.storage) + return False + + # If we're not able to create the analysis storage folder, we have to + # abort the analysis. + try: + create_folder(folder=self.storage) + except CuckooOperationalError: + self.log.error("Unable to create analysis folder %s", self.storage) + return False - return SchedulerCycleDelay.SUCCESS + return True - def find_next_serviceable_task(self, max_machines_reached: bool) -> Tuple[Optional[Task], Optional[Machine]]: - task: Optional[Task] = None - machine: Optional[Machine] = None + def check_file(self, sha256): + """Checks the integrity of the file to be analyzed.""" + sample = self.db.view_sample(self.task.sample_id) - if self.machinery_manager and not max_machines_reached: - task, machine = self.find_pending_task_to_service() - else: - task = self.find_pending_task_not_requiring_machinery() - - return task, machine - - def find_pending_task_not_requiring_machinery(self) -> Optional[Task]: - # This function must only be called when we're configured to not process any tasks - # that require machinery. - assert not self.machinery_manager - - task: Optional[Task] = None - tasks = self.db.list_tasks( - category=[category for category in self.analyzing_categories if category not in CATEGORIES_NEEDING_VM], - status=TASK_PENDING, - order_by=(Task.priority.desc(), Task.added_on), - options_not_like="node=", - limit=1, - for_update=True, - ) - if tasks: - task = tasks[0] - return task - - def find_pending_task_to_service(self) -> Tuple[Optional[Task], Optional[Machine]]: - # This function must only be called when we have the ability to use machinery. - assert self.machinery_manager - - task: Optional[Task] = None - machine: Optional[Machine] = None - # Get the list of all pending tasks in the order that they should be processed. - for task_candidate in self.db.list_tasks( - status=TASK_PENDING, - order_by=(Task.priority.desc(), Task.added_on), - options_not_like="node=", - for_update=True, - ): - if task_candidate.category not in CATEGORIES_NEEDING_VM: - # This task can definitely be processed because it doesn't need a machine. - task = task_candidate - break + if sample and sha256 != sample.sha256: + self.log.error("Target file has been modified after submission: '%s'", convert_to_printable(self.task.target)) + return False + + return True + + def store_file(self, sha256): + """Store a copy of the file being analyzed.""" + if not path_exists(self.task.target): + self.log.error( + "The file to analyze does not exist at path '%s', analysis aborted", convert_to_printable(self.task.target) + ) + return False + + binaries_dir = os.path.join(CUCKOO_ROOT, "storage", "binaries") + self.binary = os.path.join(binaries_dir, sha256) + if path_exists(self.binary): + self.log.info("File already exists at '%s'", self.binary) + else: + path_mkdir(binaries_dir, exist_ok=True) + # TODO: do we really need to abort the analysis in case we are not able to store a copy of the file? try: - machine = self.machinery_manager.find_machine_to_service_task(task_candidate) - except CuckooUnserviceableTaskError: - if self.cfg.cuckoo.fail_unserviceable: - log.info("Task #%s: Failing unserviceable task", task_candidate.id) - self.db.set_status(task_candidate.id, TASK_FAILED_ANALYSIS) - else: - log.info("Task #%s: Unserviceable task", task_candidate.id) - continue - - if machine: - task = task_candidate - break - - return task, machine - - def get_available_machine_stats(self) -> DefaultDict[str, int]: - available_machine_stats = defaultdict(int) - for machine in self.db.get_available_machines(): - for tag in machine.tags: - if tag: - available_machine_stats[tag.name] += 1 - if machine.platform: - available_machine_stats[machine.platform] += 1 - - return available_machine_stats - - def get_locked_machine_stats(self) -> DefaultDict[str, int]: - locked_machine_stats = defaultdict(int) - for machine in self.db.list_machines(locked=True): - for tag in machine.tags: - if tag: - locked_machine_stats[tag.name] += 1 - if machine.platform: - locked_machine_stats[machine.platform] += 1 - - return locked_machine_stats - - def get_pending_task_stats(self) -> DefaultDict[str, int]: - pending_task_stats = defaultdict(int) - for task in self.db.list_tasks(status=TASK_PENDING): - for tag in task.tags: - if tag: - pending_task_stats[tag.name] += 1 - if task.platform: - pending_task_stats[task.platform] += 1 - if task.machine: - pending_task_stats[task.machine] += 1 - - return pending_task_stats - - def is_short_on_disk_space(self): - """If not enough free disk space is available, then we print an - error message and wait another round. This check is ignored - when the freespace configuration variable is set to zero. + shutil.copy(self.task.target, self.binary) + except (IOError, shutil.Error): + self.log.error( + "Unable to store file from '%s' to '%s', analysis aborted", + self.task.target, + self.binary, + ) + return False + + try: + new_binary_path = os.path.join(self.storage, "binary") + if hasattr(os, "symlink"): + os.symlink(self.binary, new_binary_path) + else: + shutil.copy(self.binary, new_binary_path) + except (AttributeError, OSError) as e: + self.log.error("Unable to create symlink/copy from '%s' to '%s': %s", self.binary, self.storage, e) + + return True + + def screenshot_machine(self): + if not self.cfg.cuckoo.machinery_screenshots: + return + if self.machinery_manager is None or self.machine is None: + self.log.error("screenshot not possible, no machine is used for this analysis") + return + + # same format and filename approach here as VM-based screenshots + self.num_screenshots += 1 + screenshot_filename = f"{str(self.num_screenshots).rjust(4, '0')}.jpg" + screenshot_path = os.path.join(self.screenshot_path, screenshot_filename) + try: + self.machinery_manager.machinery.screenshot(self.machine.label, screenshot_path) + except Exception as err: + self.log.warning("Failed to take screenshot of %s: %s", self.machine.label, err) + self.num_screenshots -= 1 + + def build_options(self): + """Generate analysis options. + @return: options dict. """ - if not self.cfg.cuckoo.freespace: - return False + options = { + "id": self.task.id, + "ip": self.machine.resultserver_ip, + "port": self.machine.resultserver_port, + "category": self.task.category, + "target": self.task.target, + "package": self.task.package, + "options": self.get_machine_specific_options(self.task.options), + "enforce_timeout": self.task.enforce_timeout, + "clock": self.task.clock, + "terminate_processes": self.cfg.cuckoo.terminate_processes, + "upload_max_size": self.cfg.resultserver.upload_max_size, + "do_upload_max_size": int(self.cfg.resultserver.do_upload_max_size), + "enable_trim": int(Config("web").general.enable_trim), + "timeout": self.task.timeout or self.cfg.timeouts.default, + } + + if self.task.category == "file": + file_obj = File(self.task.target) + options["file_name"] = file_obj.get_name() + options["file_type"] = file_obj.get_type() + # if it's a PE file, collect export information to use in more smartly determining the right package to use + options["exports"] = PortableExecutable(self.task.target).get_dll_exports() + del file_obj + + # options from auxiliary.conf + for plugin in self.aux_cfg.auxiliary_modules.keys(): + options[plugin] = self.aux_cfg.auxiliary_modules[plugin] + + return options + + def category_checks(self) -> Optional[bool]: + if self.task.category in ("file", "pcap", "static"): + sha256 = File(self.task.target).get_sha256() + # Check whether the file has been changed for some unknown reason. + # And fail this analysis if it has been modified. + if not self.check_file(sha256): + self.log.debug("check file") + return False + + # Store a copy of the original file. + if not self.store_file(sha256): + self.log.debug("store file") + return False + + if self.task.category in ("pcap", "static"): + if self.task.category == "pcap": + if hasattr(os, "symlink"): + os.symlink(self.binary, os.path.join(self.storage, "dump.pcap")) + else: + shutil.copy(self.binary, os.path.join(self.storage, "dump.pcap")) + # create the logs/files directories as normally the resultserver would do it + for dirname in ("logs", "files", "aux"): + try: + path_mkdir(os.path.join(self.storage, dirname)) + except Exception: + self.log.debug("Failed to create folder %s", dirname) + return True + + return None + + @contextlib.contextmanager + def machine_running(self) -> Generator[None, None, None]: + assert self.machinery_manager and self.machine and self.guest + + try: + with self.db.session.begin(): + self.machinery_manager.start_machine(self.machine) + + yield + + # Take a memory dump of the machine before shutting it off. + self.dump_machine_memory() + + except (CuckooMachineError, CuckooGuestCriticalTimeout) as e: + # This machine has turned dead, so we'll throw an exception + # which informs the AnalysisManager that it should analyze + # this task again with another available machine. + self.log.exception(str(e)) + + # Remove the guest from the database, so that we can assign a + # new guest when the task is being analyzed with another machine. + with self.db.session.begin(): + self.db.guest_remove(self.guest.id) + self.db.assign_machine_to_task(self.task, None) + self.machinery_manager.machinery.delete_machine(self.machine.name) + + # Remove the analysis directory that has been created so + # far, as perform_analysis() is going to be doing that again. + shutil.rmtree(self.storage) + + raise CuckooDeadMachine(self.machine.name) from e + + with self.db.session.begin(): + try: + self.machinery_manager.stop_machine(self.machine) + except CuckooMachineError as e: + self.log.warning("Unable to stop machine %s: %s", self.machine.label, e) + # Explicitly rollback since we don't re-raise the exception. + self.db.session.rollback() - # Resolve the full base path to the analysis folder, just in - # case somebody decides to make a symbolic link out of it. - dir_path = os.path.join(CUCKOO_ROOT, "storage", "analyses") - need_space, space_available = free_space_monitor(dir_path, return_value=True, analysis=True) - if need_space: - log.error( - "Not enough free disk space! (Only %d MB!). You can change limits it in cuckoo.conf -> freespace", space_available + try: + # Release the analysis machine, but only if the machine is not dead. + with self.db.session.begin(): + self.machinery_manager.machinery.release(self.machine) + except CuckooMachineError as e: + self.log.error( + "Unable to release machine %s, reason %s. You might need to restore it manually", + self.machine.label, + e, ) - return need_space + + def dump_machine_memory(self) -> None: + if not self.cfg.cuckoo.memory_dump and not self.task.memory: + return + + assert self.machinery_manager and self.machine + + try: + dump_path = get_memdump_path(self.task.id) + need_space, space_available = free_space_monitor(os.path.dirname(dump_path), return_value=True) + if need_space: + self.log.error("Not enough free disk space! Could not dump ram (Only %d MB!)", space_available) + else: + self.machinery_manager.machinery.dump_memory(self.machine.label, dump_path) + except NotImplementedError: + self.log.error("The memory dump functionality is not available for the current machine manager") + + except CuckooMachineError as e: + self.log.exception(str(e)) @contextlib.contextmanager - def loop_signals(self): - signals_to_handle = (signal.SIGHUP, signal.SIGTERM, signal.SIGUSR1, signal.SIGUSR2) - for sig in signals_to_handle: - signal.signal(sig, self.signal_handler) + def result_server(self) -> Generator[None, None, None]: + try: + ResultServer().add_task(self.task, self.machine) + except Exception as e: + self.log.exception("Failed to add task to result-server") + if self.error_queue: + self.error_queue.put(e) + raise try: yield finally: - for sig in signals_to_handle: - signal.signal(sig, signal.SIG_DFL) + # After all this, we can make the ResultServer forget about the + # internal state for this analysis task. + ResultServer().del_task(self.task, self.machine) - def shutdown_machinery(self): - """Shutdown machine manager (used to kill machines that still alive).""" - if self.machinery_manager: - with self.db.session.begin(): - self.machinery_manager.machinery.shutdown() - - def signal_handler(self, signum, frame): - """Scheduler signal handler""" - sig = signal.Signals(signum) - if sig in (signal.SIGHUP, signal.SIGTERM): - log.info("received signal '%s', waiting for remaining analysis to finish before stopping", sig.name) - self.stop() - elif sig == signal.SIGUSR1: - log.info("received signal '%s', pausing new detonations, running detonations will continue until completion", sig.name) - self.loop_state = LoopState.PAUSED - elif sig == signal.SIGUSR2: - log.info("received signal '%s', resuming detonations", sig.name) - self.loop_state = LoopState.RUNNING - else: - log.info("received signal '%s', nothing to do", sig.name) + @contextlib.contextmanager + def network_routing(self) -> Generator[None, None, None]: + self.route_network() + try: + yield + finally: + # Drop the network routing rules if any. + self.unroute_network() + + @contextlib.contextmanager + def run_auxiliary(self) -> Generator[None, None, None]: + aux = RunAuxiliary(task=self.task, machine=self.machine) + + with self.db.session.begin(): + aux.start() - def start(self): - """Start scheduler.""" - if self.machinery_manager: + try: + yield + finally: with self.db.session.begin(): - self.machinery_manager.initialize_machinery() + aux.stop() - # Message queue with threads to transmit exceptions (used as IPC). - error_queue = queue.Queue() + def run_analysis_on_guest(self) -> None: + # Generate the analysis configuration file. + options = self.build_options() - # Start the logger which grabs database information - if self.cfg.cuckoo.periodic_log: - threading.Thread(target=self.thr_periodic_log, name="periodic_log", daemon=True).start() + guest_manager = GuestManager(self.machine.name, self.machine.ip, self.machine.platform, self.task.id, self) - with self.loop_signals(): - log.info("Waiting for analysis tasks") - self.loop_state = LoopState.RUNNING + with self.db.session.begin(): + if Config("web").guacamole.enabled and hasattr(self.machinery_manager.machinery, "store_vnc_port"): + self.machinery_manager.machinery.store_vnc_port(self.machine.label, self.task.id) + options["clock"] = self.db.update_clock(self.task.id) + self.db.guest_set_status(self.task.id, "starting") + guest_manager.start_analysis(options) + if guest_manager.get_status_from_db() == "starting": + guest_manager.set_status_in_db("running") + guest_manager.wait_for_completion() + + guest_manager.set_status_in_db("stopping") + + return + + def perform_analysis(self) -> bool: + """Start analysis.""" + succeeded = False + self.socks5s = _load_socks5_operational() + + # Initialize the analysis folders. + if not self.init_storage(): + self.log.debug("Failed to initialize the analysis folder") + return False + + with self.db.session.begin(): + category_early_escape = self.category_checks() + if isinstance(category_early_escape, bool): + return category_early_escape + + # At this point, we're sure that this analysis requires a machine. + assert self.machinery_manager and self.machine and self.guest + + with self.db.session.begin(): + self.machinery_manager.scale_pool(self.machine) + + self.log.info("Starting analysis of %s '%s'", self.task.category.upper(), convert_to_printable(self.task.target)) + + with self.machine_running(), self.result_server(), self.network_routing(), self.run_auxiliary(): try: - while self.loop_state in (LoopState.RUNNING, LoopState.PAUSED, LoopState.STOPPING): - sleep_time = self.do_main_loop_work(error_queue) - time.sleep(sleep_time) - try: - raise error_queue.get(block=False) - except queue.Empty: - pass + self.run_analysis_on_guest() + except CuckooGuestError as e: + self.log.exception(str(e)) + else: + succeeded = True finally: - self.loop_state = LoopState.INACTIVE - - def stop(self): - """Set loop state to stopping.""" - self.loop_state = LoopState.STOPPING - - def thr_periodic_log(self, oneshot=False): - # Ordinarily, this is the entry-point for a child thread. The oneshot parameter makes - # it easier for testing. - if not log.isEnabledFor(logging.DEBUG): - # The only purpose of this function is to log a debug message, so if debug - # logging is disabled, don't bother making all the database queries every 10 - # seconds--just return. - return + with self.db.session.begin(): + self.db.guest_stop(self.guest.id) - while True: - # Since we know we'll be logging the resulting message, just use f-strings - # because they're faster and easier to read than using %s/%d and params to - # log.debug(). - msgs = [f"# Active analysis: {self.active_analysis_count}"] + return succeeded + def launch_analysis(self) -> None: + success = False + try: + success = self.perform_analysis() + except CuckooDeadMachine: with self.db.session.begin(): - pending_task_count = self.db.count_tasks(status=TASK_PENDING) - pending_task_stats = self.get_pending_task_stats() - msgs.extend( - ( - f"# Pending Tasks: {pending_task_count}", - f"# Specific Pending Tasks: {dict(pending_task_stats)}", - ) + # Put the task back in pending so that the schedule can attempt to + # choose a new machine. + self.db.set_status(self.task.id, TASK_PENDING) + raise + else: + with self.db.session.begin(): + self.db.set_status(self.task.id, TASK_COMPLETED) + self.log.info("Completed analysis %ssuccessfully.", "" if success else "un") + + self.update_latest_symlink() + + def update_latest_symlink(self): + # We make a symbolic link ("latest") which links to the latest + # analysis - this is useful for debugging purposes. This is only + # supported under systems that support symbolic links. + if not hasattr(os, "symlink"): + return + + latest = os.path.join(CUCKOO_ROOT, "storage", "analyses", "latest") + + # First we have to remove the existing symbolic link, then we have to create the new one. + # Deal with race conditions using a lock. + with latest_symlink_lock: + try: + # As per documentation, lexists() returns True for dead symbolic links. + if os.path.lexists(latest): + path_delete(latest) + + os.symlink(self.storage, latest) + except OSError as e: + self.log.warning("Error pointing latest analysis symlink: %s", e) + + def run(self): + """Run manager thread.""" + try: + self.launch_analysis() + except Exception: + self.log.exception("failure in AnalysisManager.run") + else: + self.log.info("analysis procedure completed") + finally: + if self.done_callback: + self.done_callback(self) + + def _rooter_response_check(self): + if self.rooter_response and self.rooter_response["exception"] is not None: + raise CuckooCriticalError(f"Error execution rooter command: {self.rooter_response['exception']}") + + def route_network(self): + """Enable network routing if desired.""" + # Determine the desired routing strategy (none, internet, VPN). + routing = Config("routing") + self.route = routing.routing.route + + if self.task.route: + self.route = self.task.route + + if self.route in ("none", "None", "drop", "false"): + self.interface = None + self.rt_table = None + elif self.route == "inetsim": + self.interface = routing.inetsim.interface + elif self.route == "tor": + self.interface = routing.tor.interface + elif self.route == "internet" and routing.routing.internet != "none": + self.interface = routing.routing.internet + self.rt_table = routing.routing.rt_table + self.no_local_routing = routing.routing.no_local_routing + if routing.routing.reject_segments != "none": + self.reject_segments = routing.routing.reject_segments + if routing.routing.reject_hostports != "none": + self.reject_hostports = str(routing.routing.reject_hostports) + elif self.route in vpns: + self.interface = vpns[self.route].interface + self.rt_table = vpns[self.route].rt_table + elif self.route in self.socks5s: + self.interface = "" + else: + self.log.warning("Unknown network routing destination specified, ignoring routing for this analysis: %s", self.route) + self.interface = None + self.rt_table = None + + # Check if the network interface is still available. If a VPN dies for + # some reason, its tunX interface will no longer be available. + if self.interface and not rooter("nic_available", self.interface): + self.log.error( + "The network interface '%s' configured for this analysis is " + "not available at the moment, switching to route=none mode", + self.interface, + ) + self.route = "none" + self.interface = None + self.rt_table = None + + if self.route == "inetsim": + self.rooter_response = rooter( + "inetsim_enable", + self.machine.ip, + str(routing.inetsim.server), + str(routing.inetsim.dnsport), + str(self.cfg.resultserver.port), + str(routing.inetsim.ports), + ) + + elif self.route == "tor": + self.rooter_response = rooter( + "socks5_enable", + self.machine.ip, + str(self.cfg.resultserver.port), + str(routing.tor.dnsport), + str(routing.tor.proxyport), + ) + + elif self.route in self.socks5s: + self.rooter_response = rooter( + "socks5_enable", + self.machine.ip, + str(self.cfg.resultserver.port), + str(self.socks5s[self.route]["dnsport"]), + str(self.socks5s[self.route]["port"]), + ) + + elif self.route in ("none", "None", "drop"): + self.rooter_response = rooter("drop_enable", self.machine.ip, str(self.cfg.resultserver.port)) + + self._rooter_response_check() + + # check if the interface is up + if HAVE_NETWORKIFACES and routing.routing.verify_interface and self.interface and self.interface not in network_interfaces: + self.log.info("Network interface {} not found, falling back to dropping network traffic", self.interface) + self.interface = None + self.rt_table = None + self.route = "drop" + + if self.interface: + if self.no_local_routing: + input_interface = "dirty-line" + # Traffic from lan to machine + self.rooter_response = rooter("forward_enable", input_interface, self.machine.interface, "0.0.0.0/0", self.machine.ip) + else: + input_interface = self.machine.interface + # Traffic outbound from machine + self.rooter_response = rooter("forward_enable", input_interface, self.interface, self.machine.ip) + self._rooter_response_check() + if self.reject_segments: + self.rooter_response = rooter( + "forward_reject_enable", self.machine.interface, self.interface, self.machine.ip, self.reject_segments + ) + self._rooter_response_check() + if self.no_local_routing: + # Need for forward traffic between sandbox and CAPE + self.rooter_response = rooter( + "forward_enable", input_interface, self.interface, self.machine.ip, self.cfg.resultserver.ip, "tcp", str(self.cfg.resultserver.port) + ) + self.rooter_response = rooter( + "forward_enable", input_interface, self.machine.interface, self.cfg.resultserver.ip, self.machine.ip + ) + self._rooter_response_check() + if self.reject_hostports: + self.rooter_response = rooter( + "hostports_reject_enable", self.machine.interface, self.machine.ip, self.reject_hostports ) - if self.machinery_manager: - available_machine_count = self.db.count_machines_available() - available_machine_stats = self.get_available_machine_stats() - locked_machine_count = len(self.db.list_machines(locked=True)) - locked_machine_stats = self.get_locked_machine_stats() - total_machine_count = len(self.db.list_machines()) - msgs.extend( - ( - f"# Available Machines: {available_machine_count}", - f"# Available Specific Machines: {dict(available_machine_stats)}", - f"# Locked Machines: {locked_machine_count}", - f"# Specific Locked Machines: {dict(locked_machine_stats)}", - f"# Total Machines: {total_machine_count}", - ) + self._rooter_response_check() + + self.log.info("Enabled route '%s'.", self.route) + + if self.no_local_routing: + rooter("add_dev_to_vrf", self.machine.interface) + elif self.rt_table: + self.rooter_response = rooter("srcroute_enable", self.rt_table, self.machine.ip) + self._rooter_response_check() + + def unroute_network(self): + routing = Config("routing") + if self.interface: + if self.no_local_routing: + input_interface = "dirty-line" + # Traffic from lan to machine + self.rooter_response = rooter("forward_disable", input_interface, self.machine.interface, "0.0.0.0/0", self.machine.ip) + else: + input_interface = self.machine.interface + # Traffic outbound from machine + self.rooter_response = rooter("forward_disable", input_interface, self.interface, self.machine.ip) + self._rooter_response_check() + if self.reject_segments: + self.rooter_response = rooter( + "forward_reject_disable", input_interface, self.interface, self.machine.ip, self.reject_segments + ) + if self.no_local_routing: + self.rooter_response = rooter( + "forward_disable", input_interface, self.interface, self.machine.ip, self.cfg.resultserver.ip, "tcp", str(self.cfg.resultserver.port) + ) + self.rooter_response = rooter( + "forward_disable", input_interface, self.machine.interface, self.cfg.resultserver.ip, self.machine.ip ) - if self.cfg.cuckoo.scaling_semaphore: - lock_value = ( - f"{self.machinery_manager.machine_lock._value}/{self.machinery_manager.machine_lock._limit_value}" - ) - msgs.append(f"# Lock value: {lock_value}") - log.debug("; ".join(msgs)) - - if oneshot: - break - - time.sleep(10) - - def wait_for_running_analyses_to_finish(self) -> None: - log.info("Waiting for running analyses to finish.") - while self.analysis_threads: - thread = self.analysis_threads.pop() - log.debug("Waiting for analysis thread (%r)", thread) - thread.join() + self._rooter_response_check() + if self.reject_hostports: + self.rooter_response = rooter( + "hostports_reject_disable", self.machine.interface, self.machine.ip, self.reject_hostports + ) + self._rooter_response_check() + self.log.info("Disabled route '%s'", self.route) + + if self.no_local_routing: + rooter("delete_dev_from_vrf", self.machine.interface) + elif self.rt_table: + self.rooter_response = rooter("srcroute_disable", self.rt_table, self.machine.ip) + self._rooter_response_check() + + if self.route == "inetsim": + self.rooter_response = rooter( + "inetsim_disable", + self.machine.ip, + routing.inetsim.server, + str(routing.inetsim.dnsport), + str(self.cfg.resultserver.port), + str(routing.inetsim.ports), + ) + + elif self.route == "tor": + self.rooter_response = rooter( + "socks5_disable", + self.machine.ip, + str(self.cfg.resultserver.port), + str(routing.tor.dnsport), + str(routing.tor.proxyport), + ) + + elif self.route in self.socks5s: + self.rooter_response = rooter( + "socks5_disable", + self.machine.ip, + str(self.cfg.resultserver.port), + str(self.socks5s[self.route]["dnsport"]), + str(self.socks5s[self.route]["port"]), + ) + + elif self.route in ("none", "None", "drop"): + self.rooter_response = rooter("drop_disable", self.machine.ip, str(self.cfg.resultserver.port)) + + self._rooter_response_check() + + def get_machine_specific_options(self, task_opts: str) -> str: + """This function may be used to return an updated version of the + provided options string based on the machine that has been selected + (self.machine). + """ + return task_opts diff --git a/lib/cuckoo/core/startup.py b/lib/cuckoo/core/startup.py index aa7cd10d4ba..58ba95b0bfb 100644 --- a/lib/cuckoo/core/startup.py +++ b/lib/cuckoo/core/startup.py @@ -342,6 +342,7 @@ def init_rooter(): raise CuckooStartupError(f"Unknown rooter error: {e}") rooter("cleanup_rooter") + rooter("cleanup_vrf", routing.routing.internet) # Do not forward any packets unless we have explicitly stated so. rooter("forward_drop") @@ -424,12 +425,16 @@ def init_routing(): f"The routing table that has been configured ({routing.routing.rt_table}) for dirty line interface is not available" ) - # Disable & enable NAT on this network interface. Disable it just - # in case we still had the same rule from a previous run. - rooter("disable_nat", routing.routing.internet) - rooter("enable_nat", routing.routing.internet) - - # Populate routing table with entries from main routing table. + if routing.routing.nat: + # Disable & enable NAT on this network interface. Disable it just + # in case we still had the same rule from a previous run. + rooter("disable_nat", routing.routing.internet) + rooter("enable_nat", routing.routing.internet) + # Populate routing table with entries from main routing table. + else: + rooter("disable_nat", routing.routing.internet) + if routing.routing.no_local_routing: + rooter("init_vrf", routing.routing.rt_table, routing.routing.internet) if routing.routing.auto_rt: rooter("flush_rttable", routing.routing.rt_table) rooter("init_rttable", routing.routing.rt_table, routing.routing.internet) diff --git a/pyproject.toml b/pyproject.toml index 1482ad56a6c..35325d06426 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -61,7 +61,6 @@ djangorestframework = "3.14.0" yara-python = "4.5.0" netstruct = "1.1.2" pymongo = ">=4.0.1" -psutil = "5.8.0" # ImageHash = "4.3.1" LnkParse3 = "1.2.0" cachetools = "^5.3.0" @@ -72,6 +71,7 @@ django-allauth = "0.54.0" # https://django-allauth.readthedocs.io/en/latest/con psycopg2-binary = "^2.9.5" ruff = "0.0.290" paramiko = "3.4.0" +psutil = "5.9.8" Werkzeug = "3.0.3" packaging = "23.1" diff --git a/utils/rooter.py b/utils/rooter.py index 3ff98a4705d..af88f1e123f 100644 --- a/utils/rooter.py +++ b/utils/rooter.py @@ -6,6 +6,8 @@ import argparse import errno import grp +import ipaddress +import psutil import json import logging.handlers import os @@ -84,6 +86,13 @@ def cleanup_rooter(): p = subprocess.Popen([s.iptables_restore], stdin=subprocess.PIPE, universal_newlines=True) p.communicate(input="\n".join(cleaned)) + run_iptables("-F", "CAPE_ACCEPTED_SEGMENTS") + run_iptables("-F", "CAPE_REJECTED_SEGMENTS") + run_iptables("-N", "CAPE_ACCEPTED_SEGMENTS") + run_iptables("-N", "CAPE_REJECTED_SEGMENTS") + run_iptables("-I", "FORWARD", "-j", "CAPE_REJECTED_SEGMENTS") + run_iptables("-I", "FORWARD", "-j", "CAPE_ACCEPTED_SEGMENTS") + def nic_available(interface): """Check if specified network interface is available.""" @@ -108,6 +117,34 @@ def rt_available(rt_table): return True except subprocess.CalledProcessError: return False + + +def init_vrf(rt_table, dirty_line_dev): + run(s.ip, "link", "add", "dirty-line", "type", "vrf", "table", rt_table) + run(s.ip, "link", "set", "dev", "dirty-line", "up") + run(s.ip, "rule", "add", "l3mdev", "proto", "kernel", "prio", "1000") + run(s.ip, "rule", "add", "l3mdev", "proto", "kernel", "unreachable", "prio", "1001") + run(s.ip, "rule", "add", "lookup", "local", "proto", "kernel", "prio", "32765") + run(s.ip, "rule", "delete", "lookup", "local", "prio", "0") + run(s.ip, "link", "set", "dev", dirty_line_dev, "master", "dirty-line") + + +def cleanup_vrf(dirty_line_dev): + run(s.ip, "rule", "add", "lookup", "local", "proto", "kernel", "prio", "0") + run(s.ip, "rule", "delete", "lookup", "local", "prio", "32765") + run(s.ip, "rule", "delete", "l3mdev", "prio", "1000") + run(s.ip, "rule", "delete", "l3mdev", "unreachable", "prio", "1001") + run(s.ip, "link", "set", "dev", dirty_line_dev, "nomaster") + run(s.ip, "link", "set", "dev", "dirty-line", "down") + run(s.ip, "link", "del", "dirty-line") + + +def add_dev_to_vrf(dev): + run(s.ip, "link", "set", "dev", dev, "master", "dirty-line") + + +def delete_dev_from_vrf(dev): + run(s.ip, "link", "set", "dev", dev, "nomaster") def vpn_status(name): @@ -129,6 +166,7 @@ def forward_drop(): def state_enable(): """Enable stateful connection tracking.""" run_iptables("-A", "INPUT", "-m", "state", "--state", "ESTABLISHED,RELATED", "-j", "ACCEPT") + run_iptables("-I", "CAPE_ACCEPTED_SEGMENTS", "-m", "state", "--state", "ESTABLISHED,RELATED", "-j", "ACCEPT") def state_disable(): @@ -137,6 +175,9 @@ def state_disable(): _, err = run_iptables("-D", "INPUT", "-m", "state", "--state", "ESTABLISHED,RELATED", "-j", "ACCEPT") if err: break + _, err = run_iptables("-D", "CAPE_ACCEPTED_SEGMENTS", "-m", "state", "--state", "ESTABLISHED,RELATED", "-j", "ACCEPT") + if err: + break def enable_nat(interface): @@ -170,35 +211,90 @@ def flush_rttable(rt_table): run(settings.ip, "route", "flush", "table", rt_table) -def forward_enable(src, dst, ipaddr): - """Enable forwarding a specific IP address from one interface into - another.""" +def forward_enable(src, dst, ipaddr, accept_segments=None, proto=None, ports=None): + """Enable forwarding a specific IP address from one interface into another.""" # Delete libvirt's default FORWARD REJECT rules. e.g.: # -A FORWARD -o virbr0 -j REJECT --reject-with icmp-port-unreachable # -A FORWARD -i virbr0 -j REJECT --reject-with icmp-port-unreachable run_iptables("-D", "FORWARD", "-i", src, "-j", "REJECT") run_iptables("-D", "FORWARD", "-o", src, "-j", "REJECT") - run_iptables("-I", "FORWARD", "-i", src, "-o", dst, "--source", ipaddr, "-j", "ACCEPT") - run_iptables("-I", "FORWARD", "-i", dst, "-o", src, "--destination", ipaddr, "-j", "ACCEPT") - - -def forward_disable(src, dst, ipaddr): + if ports and (not proto or proto not in ["tcp", "udp"]): + log.debug("Invalid protocol of transport layer") + return False + if ports: + if "-" in ports: + # We need a single hyphen to indicate that it is a range + if ports.count("-") != 1: + log.debug("Invalid ports range entry: %s", ports) + return False + else: + start_port, end_port = ports.split("-") + if not start_port.isdigit() or not end_port.isdigit() or start_port > end_port: + log.debug("Invalid port range entry: %s", ports) + return False + else: + # Good to go! iptables takes port ranges as start:end + ports = ports.replace("-", ":") + # Handle a single port + else: + if not ports.isdigit(): + log.debug("Invalid port entry: %s", ports) + return False + + args = ["-I", "CAPE_ACCEPTED_SEGMENTS", "-i", src, "-o", dst, "--source", ipaddr] + if accept_segments: + args += ["--destination", accept_segments] + if ports: + args += ["-p", proto, "-m", "multiport", "--dport", ports] + args += ["-j", "ACCEPT"] + run_iptables(*args) + + +def forward_disable(src, dst, ipaddr, accept_segments=None, proto=None, ports=None): """Disable forwarding of a specific IP address from one interface into another.""" - run_iptables("-D", "FORWARD", "-i", src, "-o", dst, "--source", ipaddr, "-j", "ACCEPT") - run_iptables("-D", "FORWARD", "-i", dst, "-o", src, "--destination", ipaddr, "-j", "ACCEPT") - + if ports and (not proto or proto not in ["tcp", "udp"]): + log.debug("Invalid protocol of transport layer") + return False + if ports: + if "-" in ports: + # We need a single hyphen to indicate that it is a range + if ports.count("-") != 1: + log.debug("Invalid ports range entry: %s", ports) + return False + else: + start_port, end_port = ports.split("-") + if not start_port.isdigit() or not end_port.isdigit() or start_port > end_port: + log.debug("Invalid port range entry: %s", ports) + return False + else: + # Good to go! iptables takes port ranges as start:end + ports = ports.replace("-", ":") + # Handle a single port + else: + if not ports.isdigit(): + log.debug("Invalid port entry: %s", ports) + return False + + args = ["-D", "CAPE_ACCEPTED_SEGMENTS", "-i", src, "-o", dst, "--source", ipaddr] + if accept_segments: + args += ["--destination", accept_segments] + if ports: + args += ["-p", proto, "-m", "multiport", "--dport", ports] + args += ["-j", "ACCEPT"] + run_iptables(*args) + def forward_reject_enable(src, dst, ipaddr, reject_segments): """Enable forwarding a specific IP address from one interface into another but reject some targets network segments.""" - run_iptables("-I", "FORWARD", "-i", src, "-o", dst, "--source", ipaddr, "--destination", reject_segments, "-j", "REJECT") + run_iptables("-I", "CAPE_REJECTED_SEGMENTS", "-i", src, "-o", dst, "--source", ipaddr, "--destination", reject_segments, "-j", "REJECT") def forward_reject_disable(src, dst, ipaddr, reject_segments): """Disable forwarding a specific IP address from one interface into another but reject some targets network segments.""" - run_iptables("-D", "FORWARD", "-i", src, "-o", dst, "--source", ipaddr, "--destination", reject_segments, "-j", "REJECT") + run_iptables("-D", "CAPE_REJECTED_SEGMENTS", "-i", src, "-o", dst, "--source", ipaddr, "--destination", reject_segments, "-j", "REJECT") def hostports_reject_enable(src, ipaddr, reject_hostports): @@ -572,6 +668,10 @@ def drop_disable(ipaddr, resultserver_port): "drop_enable": drop_enable, "drop_disable": drop_disable, "cleanup_rooter": cleanup_rooter, + "init_vrf": init_vrf, + "cleanup_vrf": cleanup_vrf, + "add_dev_to_vrf": add_dev_to_vrf, + "delete_dev_from_vrf": delete_dev_from_vrf, } if __name__ == "__main__": From 317a326d453786f0f2f85bd2bb9367e70829b36c Mon Sep 17 00:00:00 2001 From: GitHub Actions Date: Sun, 2 Jun 2024 12:41:25 +0000 Subject: [PATCH 004/121] ci: Update requirements.txt --- requirements.txt | 29 ----------------------------- 1 file changed, 29 deletions(-) diff --git a/requirements.txt b/requirements.txt index ca9c42bc2d7..106328e4ba0 100644 --- a/requirements.txt +++ b/requirements.txt @@ -863,35 +863,6 @@ protobuf==4.23.4 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:e9d0be5bf34b275b9f87ba7407796556abeeba635455d036c7351f7c183ef8ff \ --hash=sha256:effeac51ab79332d44fba74660d40ae79985901ac21bca408f8dc335a81aa597 \ --hash=sha256:fee88269a090ada09ca63551bf2f573eb2424035bcf2cb1b121895b01a46594a -psutil==5.8.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:0066a82f7b1b37d334e68697faba68e5ad5e858279fd6351c8ca6024e8d6ba64 \ - --hash=sha256:02b8292609b1f7fcb34173b25e48d0da8667bc85f81d7476584d889c6e0f2131 \ - --hash=sha256:0ae6f386d8d297177fd288be6e8d1afc05966878704dad9847719650e44fc49c \ - --hash=sha256:0c9ccb99ab76025f2f0bbecf341d4656e9c1351db8cc8a03ccd62e318ab4b5c6 \ - --hash=sha256:0dd4465a039d343925cdc29023bb6960ccf4e74a65ad53e768403746a9207023 \ - --hash=sha256:12d844996d6c2b1d3881cfa6fa201fd635971869a9da945cf6756105af73d2df \ - --hash=sha256:1bff0d07e76114ec24ee32e7f7f8d0c4b0514b3fae93e3d2aaafd65d22502394 \ - --hash=sha256:245b5509968ac0bd179287d91210cd3f37add77dad385ef238b275bad35fa1c4 \ - --hash=sha256:28ff7c95293ae74bf1ca1a79e8805fcde005c18a122ca983abf676ea3466362b \ - --hash=sha256:36b3b6c9e2a34b7d7fbae330a85bf72c30b1c827a4366a07443fc4b6270449e2 \ - --hash=sha256:52de075468cd394ac98c66f9ca33b2f54ae1d9bff1ef6b67a212ee8f639ec06d \ - --hash=sha256:5da29e394bdedd9144c7331192e20c1f79283fb03b06e6abd3a8ae45ffecee65 \ - --hash=sha256:61f05864b42fedc0771d6d8e49c35f07efd209ade09a5afe6a5059e7bb7bf83d \ - --hash=sha256:6223d07a1ae93f86451d0198a0c361032c4c93ebd4bf6d25e2fb3edfad9571ef \ - --hash=sha256:6323d5d845c2785efb20aded4726636546b26d3b577aded22492908f7c1bdda7 \ - --hash=sha256:6ffe81843131ee0ffa02c317186ed1e759a145267d54fdef1bc4ea5f5931ab60 \ - --hash=sha256:74f2d0be88db96ada78756cb3a3e1b107ce8ab79f65aa885f76d7664e56928f6 \ - --hash=sha256:74fb2557d1430fff18ff0d72613c5ca30c45cdbfcddd6a5773e9fc1fe9364be8 \ - --hash=sha256:90d4091c2d30ddd0a03e0b97e6a33a48628469b99585e2ad6bf21f17423b112b \ - --hash=sha256:90f31c34d25b1b3ed6c40cdd34ff122b1887a825297c017e4cbd6796dd8b672d \ - --hash=sha256:99de3e8739258b3c3e8669cb9757c9a861b2a25ad0955f8e53ac662d66de61ac \ - --hash=sha256:c6a5fd10ce6b6344e616cf01cc5b849fa8103fbb5ba507b6b2dee4c11e84c935 \ - --hash=sha256:ce8b867423291cb65cfc6d9c4955ee9bfc1e21fe03bb50e177f2b957f1c2469d \ - --hash=sha256:d225cd8319aa1d3c85bf195c4e07d17d3cd68636b8fc97e6cf198f782f99af28 \ - --hash=sha256:ea313bb02e5e25224e518e4352af4bf5e062755160f77e4b1767dd5ccb65f876 \ - --hash=sha256:ea372bcc129394485824ae3e3ddabe67dc0b118d262c568b4d2602a7070afdb0 \ - --hash=sha256:f4634b033faf0d968bb9220dd1c793b897ab7f1189956e1aa9eae752527127d3 \ - --hash=sha256:fcc01e900c1d7bee2a37e5d6e4f9194760a93597c97fee89c4ae51701de03563 psycopg2-binary==2.9.7 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:00d8db270afb76f48a499f7bb8fa70297e66da67288471ca873db88382850bf4 \ --hash=sha256:024eaeb2a08c9a65cd5f94b31ace1ee3bb3f978cd4d079406aef85169ba01f08 \ From 430d1518807faf2af4253beab25413e832a6b178 Mon Sep 17 00:00:00 2001 From: doomedraven Date: Sat, 24 Aug 2024 08:13:31 +0200 Subject: [PATCH 005/121] Update analysis_manager.py --- lib/cuckoo/core/analysis_manager.py | 43 ++++++++++++++++++++++++++--- 1 file changed, 39 insertions(+), 4 deletions(-) diff --git a/lib/cuckoo/core/analysis_manager.py b/lib/cuckoo/core/analysis_manager.py index a61276904b9..63b5308e535 100644 --- a/lib/cuckoo/core/analysis_manager.py +++ b/lib/cuckoo/core/analysis_manager.py @@ -525,6 +525,7 @@ def route_network(self): elif self.route == "internet" and routing.routing.internet != "none": self.interface = routing.routing.internet self.rt_table = routing.routing.rt_table + self.no_local_routing = routing.routing.no_local_routing if routing.routing.reject_segments != "none": self.reject_segments = routing.routing.reject_segments if routing.routing.reject_hostports != "none": @@ -592,13 +593,29 @@ def route_network(self): self.route = "drop" if self.interface: - self.rooter_response = rooter("forward_enable", self.machine.interface, self.interface, self.machine.ip) + if self.no_local_routing: + input_interface = "dirty-line" + # Traffic from lan to machine + self.rooter_response = rooter("forward_enable", input_interface, self.machine.interface, "0.0.0.0/0", self.machine.ip) + else: + input_interface = self.machine.interface + # Traffic outbound from machine + self.rooter_response = rooter("forward_enable", input_interface, self.interface, self.machine.ip) self._rooter_response_check() if self.reject_segments: self.rooter_response = rooter( "forward_reject_enable", self.machine.interface, self.interface, self.machine.ip, self.reject_segments ) self._rooter_response_check() + if self.no_local_routing: + # Need for forward traffic between sandbox and CAPE + self.rooter_response = rooter( + "forward_enable", input_interface, self.interface, self.machine.ip, self.cfg.resultserver.ip, "tcp", str(self.cfg.resultserver.port) + ) + self.rooter_response = rooter( + "forward_enable", input_interface, self.machine.interface, self.cfg.resultserver.ip, self.machine.ip + ) + self._rooter_response_check() if self.reject_hostports: self.rooter_response = rooter( "hostports_reject_enable", self.machine.interface, self.machine.ip, self.reject_hostports @@ -607,20 +624,36 @@ def route_network(self): self.log.info("Enabled route '%s'.", self.route) - if self.rt_table: + if self.no_local_routing: + rooter("add_dev_to_vrf", self.machine.interface) + elif self.rt_table: self.rooter_response = rooter("srcroute_enable", self.rt_table, self.machine.ip) self._rooter_response_check() def unroute_network(self): routing = Config("routing") if self.interface: - self.rooter_response = rooter("forward_disable", self.machine.interface, self.interface, self.machine.ip) + if self.no_local_routing: + input_interface = "dirty-line" + # Traffic from lan to machine + self.rooter_response = rooter("forward_disable", input_interface, self.machine.interface, "0.0.0.0/0", self.machine.ip) + else: + input_interface = self.machine.interface + # Traffic outbound from machine + self.rooter_response = rooter("forward_disable", input_interface, self.interface, self.machine.ip) self._rooter_response_check() if self.reject_segments: self.rooter_response = rooter( "forward_reject_disable", self.machine.interface, self.interface, self.machine.ip, self.reject_segments ) self._rooter_response_check() + if self.no_local_routing: + self.rooter_response = rooter( + "forward_disable", input_interface, self.interface, self.machine.ip, self.cfg.resultserver.ip, "tcp", str(self.cfg.resultserver.port) + ) + self.rooter_response = rooter( + "forward_disable", input_interface, self.machine.interface, self.cfg.resultserver.ip, self.machine.ip + ) if self.reject_hostports: self.rooter_response = rooter( "hostports_reject_disable", self.machine.interface, self.machine.ip, self.reject_hostports @@ -628,7 +661,9 @@ def unroute_network(self): self._rooter_response_check() self.log.info("Disabled route '%s'", self.route) - if self.rt_table: + if self.no_local_routing: + rooter("delete_dev_from_vrf", self.machine.interface) + elif self.rt_table: self.rooter_response = rooter("srcroute_disable", self.rt_table, self.machine.ip) self._rooter_response_check() From 81e92b53efe67f7953c0498603ad31fb85f9ae63 Mon Sep 17 00:00:00 2001 From: GitHub Actions Date: Sat, 24 Aug 2024 06:14:12 +0000 Subject: [PATCH 006/121] ci: Update requirements.txt --- requirements.txt | 29 ----------------------------- 1 file changed, 29 deletions(-) diff --git a/requirements.txt b/requirements.txt index 3d682aa3cfd..ce57a86817e 100644 --- a/requirements.txt +++ b/requirements.txt @@ -920,35 +920,6 @@ protobuf==5.27.1 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:dfddb7537f789002cc4eb00752c92e67885badcc7005566f2c5de9d969d3282d \ --hash=sha256:ee52874a9e69a30271649be88ecbe69d374232e8fd0b4e4b0aaaa87f429f1631 \ --hash=sha256:f6abd0f69968792da7460d3c2cfa7d94fd74e1c21df321eb6345b963f9ec3d8d -psutil==5.8.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:0066a82f7b1b37d334e68697faba68e5ad5e858279fd6351c8ca6024e8d6ba64 \ - --hash=sha256:02b8292609b1f7fcb34173b25e48d0da8667bc85f81d7476584d889c6e0f2131 \ - --hash=sha256:0ae6f386d8d297177fd288be6e8d1afc05966878704dad9847719650e44fc49c \ - --hash=sha256:0c9ccb99ab76025f2f0bbecf341d4656e9c1351db8cc8a03ccd62e318ab4b5c6 \ - --hash=sha256:0dd4465a039d343925cdc29023bb6960ccf4e74a65ad53e768403746a9207023 \ - --hash=sha256:12d844996d6c2b1d3881cfa6fa201fd635971869a9da945cf6756105af73d2df \ - --hash=sha256:1bff0d07e76114ec24ee32e7f7f8d0c4b0514b3fae93e3d2aaafd65d22502394 \ - --hash=sha256:245b5509968ac0bd179287d91210cd3f37add77dad385ef238b275bad35fa1c4 \ - --hash=sha256:28ff7c95293ae74bf1ca1a79e8805fcde005c18a122ca983abf676ea3466362b \ - --hash=sha256:36b3b6c9e2a34b7d7fbae330a85bf72c30b1c827a4366a07443fc4b6270449e2 \ - --hash=sha256:52de075468cd394ac98c66f9ca33b2f54ae1d9bff1ef6b67a212ee8f639ec06d \ - --hash=sha256:5da29e394bdedd9144c7331192e20c1f79283fb03b06e6abd3a8ae45ffecee65 \ - --hash=sha256:61f05864b42fedc0771d6d8e49c35f07efd209ade09a5afe6a5059e7bb7bf83d \ - --hash=sha256:6223d07a1ae93f86451d0198a0c361032c4c93ebd4bf6d25e2fb3edfad9571ef \ - --hash=sha256:6323d5d845c2785efb20aded4726636546b26d3b577aded22492908f7c1bdda7 \ - --hash=sha256:6ffe81843131ee0ffa02c317186ed1e759a145267d54fdef1bc4ea5f5931ab60 \ - --hash=sha256:74f2d0be88db96ada78756cb3a3e1b107ce8ab79f65aa885f76d7664e56928f6 \ - --hash=sha256:74fb2557d1430fff18ff0d72613c5ca30c45cdbfcddd6a5773e9fc1fe9364be8 \ - --hash=sha256:90d4091c2d30ddd0a03e0b97e6a33a48628469b99585e2ad6bf21f17423b112b \ - --hash=sha256:90f31c34d25b1b3ed6c40cdd34ff122b1887a825297c017e4cbd6796dd8b672d \ - --hash=sha256:99de3e8739258b3c3e8669cb9757c9a861b2a25ad0955f8e53ac662d66de61ac \ - --hash=sha256:c6a5fd10ce6b6344e616cf01cc5b849fa8103fbb5ba507b6b2dee4c11e84c935 \ - --hash=sha256:ce8b867423291cb65cfc6d9c4955ee9bfc1e21fe03bb50e177f2b957f1c2469d \ - --hash=sha256:d225cd8319aa1d3c85bf195c4e07d17d3cd68636b8fc97e6cf198f782f99af28 \ - --hash=sha256:ea313bb02e5e25224e518e4352af4bf5e062755160f77e4b1767dd5ccb65f876 \ - --hash=sha256:ea372bcc129394485824ae3e3ddabe67dc0b118d262c568b4d2602a7070afdb0 \ - --hash=sha256:f4634b033faf0d968bb9220dd1c793b897ab7f1189956e1aa9eae752527127d3 \ - --hash=sha256:fcc01e900c1d7bee2a37e5d6e4f9194760a93597c97fee89c4ae51701de03563 psycopg2-binary==2.9.7 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:00d8db270afb76f48a499f7bb8fa70297e66da67288471ca873db88382850bf4 \ --hash=sha256:024eaeb2a08c9a65cd5f94b31ace1ee3bb3f978cd4d079406aef85169ba01f08 \ From 379703789821739978eff52034d93dd966f29258 Mon Sep 17 00:00:00 2001 From: doomedraven Date: Sat, 24 Aug 2024 08:22:33 +0200 Subject: [PATCH 007/121] Update poetry.lock --- poetry.lock | 98 ++++++++++++----------------------------------------- 1 file changed, 21 insertions(+), 77 deletions(-) diff --git a/poetry.lock b/poetry.lock index d8448dd7a91..8d786b72acb 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1604,16 +1604,6 @@ files = [ {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-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:f698de3fd0c4e6972b92290a45bd9b1536bffe8c6759c62471efaa8acb4c37bc"}, - {file = "MarkupSafe-2.1.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:aa57bd9cf8ae831a362185ee444e15a93ecb2e344c8e52e4d721ea3ab6ef1823"}, - {file = "MarkupSafe-2.1.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ffcc3f7c66b5f5b7931a5aa68fc9cecc51e685ef90282f4a82f0f5e9b704ad11"}, - {file = "MarkupSafe-2.1.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:47d4f1c5f80fc62fdd7777d0d40a2e9dda0a05883ab11374334f6c4de38adffd"}, - {file = "MarkupSafe-2.1.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1f67c7038d560d92149c060157d623c542173016c4babc0c1913cca0564b9939"}, - {file = "MarkupSafe-2.1.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:9aad3c1755095ce347e26488214ef77e0485a3c34a50c5a5e2471dff60b9dd9c"}, - {file = "MarkupSafe-2.1.3-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:14ff806850827afd6b07a5f32bd917fb7f45b046ba40c57abdb636674a8b559c"}, - {file = "MarkupSafe-2.1.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8f9293864fe09b8149f0cc42ce56e3f0e54de883a9de90cd427f191c346eb2e1"}, - {file = "MarkupSafe-2.1.3-cp312-cp312-win32.whl", hash = "sha256:715d3562f79d540f251b99ebd6d8baa547118974341db04f5ad06d5ea3eb8007"}, - {file = "MarkupSafe-2.1.3-cp312-cp312-win_amd64.whl", hash = "sha256:1b8dd8c3fd14349433c79fa8abeb573a55fc0fdd769133baac1f5e07abf54aeb"}, {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"}, @@ -2262,43 +2252,31 @@ files = [ [[package]] name = "psutil" -version = "5.8.0" +version = "5.9.8" description = "Cross-platform lib for process and system monitoring in Python." optional = false -python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -files = [ - {file = "psutil-5.8.0-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:0066a82f7b1b37d334e68697faba68e5ad5e858279fd6351c8ca6024e8d6ba64"}, - {file = "psutil-5.8.0-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:0ae6f386d8d297177fd288be6e8d1afc05966878704dad9847719650e44fc49c"}, - {file = "psutil-5.8.0-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:12d844996d6c2b1d3881cfa6fa201fd635971869a9da945cf6756105af73d2df"}, - {file = "psutil-5.8.0-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:02b8292609b1f7fcb34173b25e48d0da8667bc85f81d7476584d889c6e0f2131"}, - {file = "psutil-5.8.0-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:6ffe81843131ee0ffa02c317186ed1e759a145267d54fdef1bc4ea5f5931ab60"}, - {file = "psutil-5.8.0-cp27-none-win32.whl", hash = "sha256:ea313bb02e5e25224e518e4352af4bf5e062755160f77e4b1767dd5ccb65f876"}, - {file = "psutil-5.8.0-cp27-none-win_amd64.whl", hash = "sha256:5da29e394bdedd9144c7331192e20c1f79283fb03b06e6abd3a8ae45ffecee65"}, - {file = "psutil-5.8.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:74fb2557d1430fff18ff0d72613c5ca30c45cdbfcddd6a5773e9fc1fe9364be8"}, - {file = "psutil-5.8.0-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:74f2d0be88db96ada78756cb3a3e1b107ce8ab79f65aa885f76d7664e56928f6"}, - {file = "psutil-5.8.0-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:99de3e8739258b3c3e8669cb9757c9a861b2a25ad0955f8e53ac662d66de61ac"}, - {file = "psutil-5.8.0-cp36-cp36m-win32.whl", hash = "sha256:36b3b6c9e2a34b7d7fbae330a85bf72c30b1c827a4366a07443fc4b6270449e2"}, - {file = "psutil-5.8.0-cp36-cp36m-win_amd64.whl", hash = "sha256:52de075468cd394ac98c66f9ca33b2f54ae1d9bff1ef6b67a212ee8f639ec06d"}, - {file = "psutil-5.8.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:c6a5fd10ce6b6344e616cf01cc5b849fa8103fbb5ba507b6b2dee4c11e84c935"}, - {file = "psutil-5.8.0-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:61f05864b42fedc0771d6d8e49c35f07efd209ade09a5afe6a5059e7bb7bf83d"}, - {file = "psutil-5.8.0-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:0dd4465a039d343925cdc29023bb6960ccf4e74a65ad53e768403746a9207023"}, - {file = "psutil-5.8.0-cp37-cp37m-win32.whl", hash = "sha256:1bff0d07e76114ec24ee32e7f7f8d0c4b0514b3fae93e3d2aaafd65d22502394"}, - {file = "psutil-5.8.0-cp37-cp37m-win_amd64.whl", hash = "sha256:fcc01e900c1d7bee2a37e5d6e4f9194760a93597c97fee89c4ae51701de03563"}, - {file = "psutil-5.8.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6223d07a1ae93f86451d0198a0c361032c4c93ebd4bf6d25e2fb3edfad9571ef"}, - {file = "psutil-5.8.0-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:d225cd8319aa1d3c85bf195c4e07d17d3cd68636b8fc97e6cf198f782f99af28"}, - {file = "psutil-5.8.0-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:28ff7c95293ae74bf1ca1a79e8805fcde005c18a122ca983abf676ea3466362b"}, - {file = "psutil-5.8.0-cp38-cp38-win32.whl", hash = "sha256:ce8b867423291cb65cfc6d9c4955ee9bfc1e21fe03bb50e177f2b957f1c2469d"}, - {file = "psutil-5.8.0-cp38-cp38-win_amd64.whl", hash = "sha256:90f31c34d25b1b3ed6c40cdd34ff122b1887a825297c017e4cbd6796dd8b672d"}, - {file = "psutil-5.8.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6323d5d845c2785efb20aded4726636546b26d3b577aded22492908f7c1bdda7"}, - {file = "psutil-5.8.0-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:245b5509968ac0bd179287d91210cd3f37add77dad385ef238b275bad35fa1c4"}, - {file = "psutil-5.8.0-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:90d4091c2d30ddd0a03e0b97e6a33a48628469b99585e2ad6bf21f17423b112b"}, - {file = "psutil-5.8.0-cp39-cp39-win32.whl", hash = "sha256:ea372bcc129394485824ae3e3ddabe67dc0b118d262c568b4d2602a7070afdb0"}, - {file = "psutil-5.8.0-cp39-cp39-win_amd64.whl", hash = "sha256:f4634b033faf0d968bb9220dd1c793b897ab7f1189956e1aa9eae752527127d3"}, - {file = "psutil-5.8.0.tar.gz", hash = "sha256:0c9ccb99ab76025f2f0bbecf341d4656e9c1351db8cc8a03ccd62e318ab4b5c6"}, +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" +files = [ + {file = "psutil-5.9.8-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:26bd09967ae00920df88e0352a91cff1a78f8d69b3ecabbfe733610c0af486c8"}, + {file = "psutil-5.9.8-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:05806de88103b25903dff19bb6692bd2e714ccf9e668d050d144012055cbca73"}, + {file = "psutil-5.9.8-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:611052c4bc70432ec770d5d54f64206aa7203a101ec273a0cd82418c86503bb7"}, + {file = "psutil-5.9.8-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:50187900d73c1381ba1454cf40308c2bf6f34268518b3f36a9b663ca87e65e36"}, + {file = "psutil-5.9.8-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:02615ed8c5ea222323408ceba16c60e99c3f91639b07da6373fb7e6539abc56d"}, + {file = "psutil-5.9.8-cp27-none-win32.whl", hash = "sha256:36f435891adb138ed3c9e58c6af3e2e6ca9ac2f365efe1f9cfef2794e6c93b4e"}, + {file = "psutil-5.9.8-cp27-none-win_amd64.whl", hash = "sha256:bd1184ceb3f87651a67b2708d4c3338e9b10c5df903f2e3776b62303b26cb631"}, + {file = "psutil-5.9.8-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:aee678c8720623dc456fa20659af736241f575d79429a0e5e9cf88ae0605cc81"}, + {file = "psutil-5.9.8-cp36-abi3-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8cb6403ce6d8e047495a701dc7c5bd788add903f8986d523e3e20b98b733e421"}, + {file = "psutil-5.9.8-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d06016f7f8625a1825ba3732081d77c94589dca78b7a3fc072194851e88461a4"}, + {file = "psutil-5.9.8-cp36-cp36m-win32.whl", hash = "sha256:7d79560ad97af658a0f6adfef8b834b53f64746d45b403f225b85c5c2c140eee"}, + {file = "psutil-5.9.8-cp36-cp36m-win_amd64.whl", hash = "sha256:27cc40c3493bb10de1be4b3f07cae4c010ce715290a5be22b98493509c6299e2"}, + {file = "psutil-5.9.8-cp37-abi3-win32.whl", hash = "sha256:bc56c2a1b0d15aa3eaa5a60c9f3f8e3e565303b465dbf57a1b730e7a2b9844e0"}, + {file = "psutil-5.9.8-cp37-abi3-win_amd64.whl", hash = "sha256:8db4c1b57507eef143a15a6884ca10f7c73876cdf5d51e713151c1236a0e68cf"}, + {file = "psutil-5.9.8-cp38-abi3-macosx_11_0_arm64.whl", hash = "sha256:d16bbddf0693323b8c6123dd804100241da461e41d6e332fb0ba6058f630f8c8"}, + {file = "psutil-5.9.8.tar.gz", hash = "sha256:6be126e3225486dff286a8fb9a06246a5253f4c7c53b475ea5f5ac934e64194c"}, ] [package.extras] -test = ["enum34", "ipaddress", "mock", "pywin32", "unittest2", "wmi"] +test = ["enum34", "ipaddress", "mock", "pywin32", "wmi"] [[package]] name = "psycopg2-binary" @@ -2594,8 +2572,6 @@ files = [ {file = "pydeep2-0.5.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2283893e25826b547dd1e5c71a010e86ddfd7270e2f2b8c90973c1d7984c7eb7"}, {file = "pydeep2-0.5.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f248e3161deb53d46a9368a7c164e36d83004faf2f11625d47a5cf23a6bdd2cb"}, {file = "pydeep2-0.5.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a13fca9be89a9fa8d92a4f49d7b9191eef94555f8ddf030fb2be4c8c15ad618c"}, - {file = "pydeep2-0.5.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d1cb4757db97ac15ddf034c21cd6bab984f841586b6d53984e63c9a7803b2cd4"}, - {file = "pydeep2-0.5.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7809a1d6640bdbee68f075d53229d05229e11b4711f232728dd540f68e6483a4"}, {file = "pydeep2-0.5.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0fedc1c9660cb5d0b73ad0b5f1dbffe16990e6721cbfc6454571a4b9882d0ea4"}, {file = "pydeep2-0.5.1-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7ca68f7d63e2ef510d410d20b223e8e97df41707fb50c4c526b6dd1d8698d9e6"}, {file = "pydeep2-0.5.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:199d05d8b4b7544509a2ba4802ead4b41dfe7859e0ecea9d9be9e41939f11660"}, @@ -3156,7 +3132,6 @@ files = [ {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938"}, {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d"}, {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515"}, - {file = "PyYAML-6.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:326c013efe8048858a6d312ddd31d56e468118ad4cdeda36c719bf5bb6192290"}, {file = "PyYAML-6.0.1-cp310-cp310-win32.whl", hash = "sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924"}, {file = "PyYAML-6.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d"}, {file = "PyYAML-6.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007"}, @@ -3164,16 +3139,8 @@ files = [ {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d"}, {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc"}, {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673"}, - {file = "PyYAML-6.0.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e7d73685e87afe9f3b36c799222440d6cf362062f78be1013661b00c5c6f678b"}, {file = "PyYAML-6.0.1-cp311-cp311-win32.whl", hash = "sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741"}, {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"}, - {file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"}, - {file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"}, - {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a08c6f0fe150303c1c6b71ebcd7213c2858041a7e01975da3a99aed1e7a378ef"}, - {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"}, - {file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"}, - {file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"}, - {file = "PyYAML-6.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:0d3304d8c0adc42be59c5f8a4d9e3d7379e6955ad754aa9d6ab7a398b59dd1df"}, {file = "PyYAML-6.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47"}, {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98"}, {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c"}, @@ -3190,7 +3157,6 @@ files = [ {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5"}, {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696"}, {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735"}, - {file = "PyYAML-6.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:49a183be227561de579b4a36efbb21b3eab9651dd81b1858589f796549873dd6"}, {file = "PyYAML-6.0.1-cp38-cp38-win32.whl", hash = "sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206"}, {file = "PyYAML-6.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62"}, {file = "PyYAML-6.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8"}, @@ -3198,7 +3164,6 @@ files = [ {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6"}, {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0"}, {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c"}, - {file = "PyYAML-6.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:04ac92ad1925b2cff1db0cfebffb6ffc43457495c9b3c39d3fcae417d7125dc5"}, {file = "PyYAML-6.0.1-cp39-cp39-win32.whl", hash = "sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c"}, {file = "PyYAML-6.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486"}, {file = "PyYAML-6.0.1.tar.gz", hash = "sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43"}, @@ -3644,51 +3609,30 @@ description = "Database Abstraction Library" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7" files = [ - {file = "SQLAlchemy-1.4.50-cp310-cp310-macosx_11_0_x86_64.whl", hash = "sha256:54138aa80d2dedd364f4e8220eef284c364d3270aaef621570aa2bd99902e2e8"}, {file = "SQLAlchemy-1.4.50-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d00665725063692c42badfd521d0c4392e83c6c826795d38eb88fb108e5660e5"}, {file = "SQLAlchemy-1.4.50-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:85292ff52ddf85a39367057c3d7968a12ee1fb84565331a36a8fead346f08796"}, {file = "SQLAlchemy-1.4.50-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:d0fed0f791d78e7767c2db28d34068649dfeea027b83ed18c45a423f741425cb"}, {file = "SQLAlchemy-1.4.50-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:db4db3c08ffbb18582f856545f058a7a5e4ab6f17f75795ca90b3c38ee0a8ba4"}, - {file = "SQLAlchemy-1.4.50-cp310-cp310-win32.whl", hash = "sha256:6c78e3fb4a58e900ec433b6b5f4efe1a0bf81bbb366ae7761c6e0051dd310ee3"}, - {file = "SQLAlchemy-1.4.50-cp310-cp310-win_amd64.whl", hash = "sha256:d55f7a33e8631e15af1b9e67c9387c894fedf6deb1a19f94be8731263c51d515"}, - {file = "SQLAlchemy-1.4.50-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:324b1fdd50e960a93a231abb11d7e0f227989a371e3b9bd4f1259920f15d0304"}, {file = "SQLAlchemy-1.4.50-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:14b0cacdc8a4759a1e1bd47dc3ee3f5db997129eb091330beda1da5a0e9e5bd7"}, {file = "SQLAlchemy-1.4.50-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1fb9cb60e0f33040e4f4681e6658a7eb03b5cb4643284172f91410d8c493dace"}, - {file = "SQLAlchemy-1.4.50-cp311-cp311-win32.whl", hash = "sha256:8bdab03ff34fc91bfab005e96f672ae207d87e0ac7ee716d74e87e7046079d8b"}, - {file = "SQLAlchemy-1.4.50-cp311-cp311-win_amd64.whl", hash = "sha256:52e01d60b06f03b0a5fc303c8aada405729cbc91a56a64cead8cb7c0b9b13c1a"}, - {file = "SQLAlchemy-1.4.50-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:77fde9bf74f4659864c8e26ac08add8b084e479b9a18388e7db377afc391f926"}, {file = "SQLAlchemy-1.4.50-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c4cb501d585aa74a0f86d0ea6263b9c5e1d1463f8f9071392477fd401bd3c7cc"}, {file = "SQLAlchemy-1.4.50-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8a7a66297e46f85a04d68981917c75723e377d2e0599d15fbe7a56abed5e2d75"}, - {file = "SQLAlchemy-1.4.50-cp312-cp312-win32.whl", hash = "sha256:e86c920b7d362cfa078c8b40e7765cbc34efb44c1007d7557920be9ddf138ec7"}, - {file = "SQLAlchemy-1.4.50-cp312-cp312-win_amd64.whl", hash = "sha256:6b3df20fbbcbcd1c1d43f49ccf3eefb370499088ca251ded632b8cbaee1d497d"}, - {file = "SQLAlchemy-1.4.50-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:fb9adc4c6752d62c6078c107d23327aa3023ef737938d0135ece8ffb67d07030"}, {file = "SQLAlchemy-1.4.50-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c1db0221cb26d66294f4ca18c533e427211673ab86c1fbaca8d6d9ff78654293"}, {file = "SQLAlchemy-1.4.50-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0b7dbe6369677a2bea68fe9812c6e4bbca06ebfa4b5cde257b2b0bf208709131"}, {file = "SQLAlchemy-1.4.50-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:a9bddb60566dc45c57fd0a5e14dd2d9e5f106d2241e0a2dc0c1da144f9444516"}, {file = "SQLAlchemy-1.4.50-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:82dd4131d88395df7c318eeeef367ec768c2a6fe5bd69423f7720c4edb79473c"}, - {file = "SQLAlchemy-1.4.50-cp36-cp36m-win32.whl", hash = "sha256:1b9c4359d3198f341480e57494471201e736de459452caaacf6faa1aca852bd8"}, - {file = "SQLAlchemy-1.4.50-cp36-cp36m-win_amd64.whl", hash = "sha256:35e4520f7c33c77f2636a1e860e4f8cafaac84b0b44abe5de4c6c8890b6aaa6d"}, - {file = "SQLAlchemy-1.4.50-cp37-cp37m-macosx_11_0_x86_64.whl", hash = "sha256:f5b1fb2943d13aba17795a770d22a2ec2214fc65cff46c487790192dda3a3ee7"}, {file = "SQLAlchemy-1.4.50-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:273505fcad22e58cc67329cefab2e436006fc68e3c5423056ee0513e6523268a"}, {file = "SQLAlchemy-1.4.50-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a3257a6e09626d32b28a0c5b4f1a97bced585e319cfa90b417f9ab0f6145c33c"}, {file = "SQLAlchemy-1.4.50-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:d69738d582e3a24125f0c246ed8d712b03bd21e148268421e4a4d09c34f521a5"}, {file = "SQLAlchemy-1.4.50-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:34e1c5d9cd3e6bf3d1ce56971c62a40c06bfc02861728f368dcfec8aeedb2814"}, - {file = "SQLAlchemy-1.4.50-cp37-cp37m-win32.whl", hash = "sha256:7b4396452273aedda447e5aebe68077aa7516abf3b3f48408793e771d696f397"}, - {file = "SQLAlchemy-1.4.50-cp37-cp37m-win_amd64.whl", hash = "sha256:752f9df3dddbacb5f42d8405b2d5885675a93501eb5f86b88f2e47a839cf6337"}, - {file = "SQLAlchemy-1.4.50-cp38-cp38-macosx_11_0_x86_64.whl", hash = "sha256:35c7ed095a4b17dbc8813a2bfb38b5998318439da8e6db10a804df855e3a9e3a"}, {file = "SQLAlchemy-1.4.50-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f1fcee5a2c859eecb4ed179edac5ffbc7c84ab09a5420219078ccc6edda45436"}, {file = "SQLAlchemy-1.4.50-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fbaf6643a604aa17e7a7afd74f665f9db882df5c297bdd86c38368f2c471f37d"}, {file = "SQLAlchemy-1.4.50-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:2e70e0673d7d12fa6cd363453a0d22dac0d9978500aa6b46aa96e22690a55eab"}, {file = "SQLAlchemy-1.4.50-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8b881ac07d15fb3e4f68c5a67aa5cdaf9eb8f09eb5545aaf4b0a5f5f4659be18"}, - {file = "SQLAlchemy-1.4.50-cp38-cp38-win32.whl", hash = "sha256:8a219688297ee5e887a93ce4679c87a60da4a5ce62b7cb4ee03d47e9e767f558"}, - {file = "SQLAlchemy-1.4.50-cp38-cp38-win_amd64.whl", hash = "sha256:a648770db002452703b729bdcf7d194e904aa4092b9a4d6ab185b48d13252f63"}, - {file = "SQLAlchemy-1.4.50-cp39-cp39-macosx_11_0_x86_64.whl", hash = "sha256:4be4da121d297ce81e1ba745a0a0521c6cf8704634d7b520e350dce5964c71ac"}, {file = "SQLAlchemy-1.4.50-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3f6997da81114daef9203d30aabfa6b218a577fc2bd797c795c9c88c9eb78d49"}, {file = "SQLAlchemy-1.4.50-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bdb77e1789e7596b77fd48d99ec1d2108c3349abd20227eea0d48d3f8cf398d9"}, {file = "SQLAlchemy-1.4.50-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:128a948bd40780667114b0297e2cc6d657b71effa942e0a368d8cc24293febb3"}, {file = "SQLAlchemy-1.4.50-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f2d526aeea1bd6a442abc7c9b4b00386fd70253b80d54a0930c0a216230a35be"}, - {file = "SQLAlchemy-1.4.50-cp39-cp39-win32.whl", hash = "sha256:a7c9b9dca64036008962dd6b0d9fdab2dfdbf96c82f74dbd5d86006d8d24a30f"}, - {file = "SQLAlchemy-1.4.50-cp39-cp39-win_amd64.whl", hash = "sha256:df200762efbd672f7621b253721644642ff04a6ff957236e0e2fe56d9ca34d2c"}, {file = "SQLAlchemy-1.4.50.tar.gz", hash = "sha256:3b97ddf509fc21e10b09403b5219b06c5b558b27fc2453150274fa4e70707dbf"}, ] @@ -4416,4 +4360,4 @@ testing = ["coverage (>=5.0.3)", "zope.event", "zope.testing"] [metadata] lock-version = "2.0" python-versions = "^3.10" -content-hash = "e6e3a0a5c8394f05f3b69fb58bf9b4c7cf6800caf6d5631d51fbe295506c7efc" +content-hash = "36985dd1c045020de022b9b5e643f01cc6c663383754dd7c2ac319a7b53c327f" From 222934cf2dd2891d79f40a3269c8590e10d86039 Mon Sep 17 00:00:00 2001 From: GitHub Actions Date: Sat, 24 Aug 2024 06:23:06 +0000 Subject: [PATCH 008/121] ci: Update requirements.txt --- requirements.txt | 63 ++++++++++++++---------------------------------- 1 file changed, 18 insertions(+), 45 deletions(-) diff --git a/requirements.txt b/requirements.txt index 1bb13dd6b0d..f06baa9043b 100644 --- a/requirements.txt +++ b/requirements.txt @@ -555,11 +555,8 @@ markupsafe==2.1.3 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:0a4e4a1aff6c7ac4cd55792abf96c915634c2b97e3cc1c7129578aa68ebd754e \ --hash=sha256:10bbfe99883db80bdbaff2dcf681dfc6533a614f700da1287707e8a5d78a8431 \ --hash=sha256:134da1eca9ec0ae528110ccc9e48041e0828d79f24121a1a146161103c76e686 \ - --hash=sha256:14ff806850827afd6b07a5f32bd917fb7f45b046ba40c57abdb636674a8b559c \ --hash=sha256:1577735524cdad32f9f694208aa75e422adba74f1baee7551620e43a3141f559 \ --hash=sha256:1b40069d487e7edb2676d3fbdb2b0829ffa2cd63a2ec26c4938b2d34391b4ecc \ - --hash=sha256:1b8dd8c3fd14349433c79fa8abeb573a55fc0fdd769133baac1f5e07abf54aeb \ - --hash=sha256:1f67c7038d560d92149c060157d623c542173016c4babc0c1913cca0564b9939 \ --hash=sha256:282c2cb35b5b673bbcadb33a585408104df04f14b2d9b01d4c345a3b92861c2c \ --hash=sha256:2c1b19b3aaacc6e57b7e25710ff571c24d6c3613a45e905b1fde04d691b98ee0 \ --hash=sha256:2ef12179d3a291be237280175b542c07a36e7f60718296278d8593d21ca937d4 \ @@ -567,7 +564,6 @@ markupsafe==2.1.3 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:3c0fae6c3be832a0a0473ac912810b2877c8cb9d76ca48de1ed31e1c68386575 \ --hash=sha256:3fd4abcb888d15a94f32b75d8fd18ee162ca0c064f35b11134be77050296d6ba \ --hash=sha256:42de32b22b6b804f42c5d98be4f7e5e977ecdd9ee9b660fda1a3edf03b11792d \ - --hash=sha256:47d4f1c5f80fc62fdd7777d0d40a2e9dda0a05883ab11374334f6c4de38adffd \ --hash=sha256:504b320cd4b7eff6f968eddf81127112db685e81f7e36e75f9f84f0df46041c3 \ --hash=sha256:525808b8019e36eb524b8c68acdd63a37e75714eac50e988180b169d64480a00 \ --hash=sha256:56d9f2ecac662ca1611d183feb03a3fa4406469dafe241673d521dd5ae92a155 \ @@ -576,7 +572,6 @@ markupsafe==2.1.3 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:68e78619a61ecf91e76aa3e6e8e33fc4894a2bebe93410754bd28fce0a8a4f9f \ --hash=sha256:69c0f17e9f5a7afdf2cc9fb2d1ce6aabdb3bafb7f38017c0b77862bcec2bbad8 \ --hash=sha256:6b2b56950d93e41f33b4223ead100ea0fe11f8e6ee5f641eb753ce4b77a7042b \ - --hash=sha256:715d3562f79d540f251b99ebd6d8baa547118974341db04f5ad06d5ea3eb8007 \ --hash=sha256:787003c0ddb00500e49a10f2844fac87aa6ce977b90b0feaaf9de23c22508b24 \ --hash=sha256:7ef3cb2ebbf91e330e3bb937efada0edd9003683db6b57bb108c4001f37a02ea \ --hash=sha256:8023faf4e01efadfa183e863fefde0046de576c6f14659e8782065bcece22198 \ @@ -584,12 +579,9 @@ markupsafe==2.1.3 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:8afafd99945ead6e075b973fefa56379c5b5c53fd8937dad92c662da5d8fd5ee \ --hash=sha256:8c41976a29d078bb235fea9b2ecd3da465df42a562910f9022f1a03107bd02be \ --hash=sha256:8e254ae696c88d98da6555f5ace2279cf7cd5b3f52be2b5cf97feafe883b58d2 \ - --hash=sha256:8f9293864fe09b8149f0cc42ce56e3f0e54de883a9de90cd427f191c346eb2e1 \ --hash=sha256:9402b03f1a1b4dc4c19845e5c749e3ab82d5078d16a2a4c2cd2df62d57bb0707 \ --hash=sha256:962f82a3086483f5e5f64dbad880d31038b698494799b097bc59c2edf392fce6 \ - --hash=sha256:9aad3c1755095ce347e26488214ef77e0485a3c34a50c5a5e2471dff60b9dd9c \ --hash=sha256:9dcdfd0eaf283af041973bff14a2e143b8bd64e069f4c383416ecd79a81aab58 \ - --hash=sha256:aa57bd9cf8ae831a362185ee444e15a93ecb2e344c8e52e4d721ea3ab6ef1823 \ --hash=sha256:aa7bd130efab1c280bed0f45501b7c8795f9fdbeb02e965371bbef3523627779 \ --hash=sha256:ab4a0df41e7c16a1392727727e7998a467472d0ad65f3ad5e6e765015df08636 \ --hash=sha256:ad9e82fb8f09ade1c3e1b996a6337afac2b8b9e365f926f5a61aacc71adc5b3c \ @@ -608,9 +600,7 @@ markupsafe==2.1.3 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:df0be2b576a7abbf737b1575f048c23fb1d769f267ec4358296f31c2479db8f9 \ --hash=sha256:e09031c87a1e51556fdcb46e5bd4f59dfb743061cf93c4d6831bf894f125eb57 \ --hash=sha256:e4dd52d80b8c83fdce44e12478ad2e85c64ea965e75d66dbeafb0a3e77308fcc \ - --hash=sha256:f698de3fd0c4e6972b92290a45bd9b1536bffe8c6759c62471efaa8acb4c37bc \ - --hash=sha256:fec21693218efe39aa7f8599346e90c705afa52c5b31ae019b2e57e8f6542bb2 \ - --hash=sha256:ffcc3f7c66b5f5b7931a5aa68fc9cecc51e685ef90282f4a82f0f5e9b704ad11 + --hash=sha256:fec21693218efe39aa7f8599346e90c705afa52c5b31ae019b2e57e8f6542bb2 maxminddb==2.5.1 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:0702da59b9670a72761b65cb1a52bc3032d8f6799bdab641cb8350ad5740580b \ --hash=sha256:0a21abd85e10e5e0f60244b49c3db17e7e48befd4972e62a62833d91e2acbb49 \ @@ -930,6 +920,23 @@ protobuf==5.27.1 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:dfddb7537f789002cc4eb00752c92e67885badcc7005566f2c5de9d969d3282d \ --hash=sha256:ee52874a9e69a30271649be88ecbe69d374232e8fd0b4e4b0aaaa87f429f1631 \ --hash=sha256:f6abd0f69968792da7460d3c2cfa7d94fd74e1c21df321eb6345b963f9ec3d8d +psutil==5.9.8 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:02615ed8c5ea222323408ceba16c60e99c3f91639b07da6373fb7e6539abc56d \ + --hash=sha256:05806de88103b25903dff19bb6692bd2e714ccf9e668d050d144012055cbca73 \ + --hash=sha256:26bd09967ae00920df88e0352a91cff1a78f8d69b3ecabbfe733610c0af486c8 \ + --hash=sha256:27cc40c3493bb10de1be4b3f07cae4c010ce715290a5be22b98493509c6299e2 \ + --hash=sha256:36f435891adb138ed3c9e58c6af3e2e6ca9ac2f365efe1f9cfef2794e6c93b4e \ + --hash=sha256:50187900d73c1381ba1454cf40308c2bf6f34268518b3f36a9b663ca87e65e36 \ + --hash=sha256:611052c4bc70432ec770d5d54f64206aa7203a101ec273a0cd82418c86503bb7 \ + --hash=sha256:6be126e3225486dff286a8fb9a06246a5253f4c7c53b475ea5f5ac934e64194c \ + --hash=sha256:7d79560ad97af658a0f6adfef8b834b53f64746d45b403f225b85c5c2c140eee \ + --hash=sha256:8cb6403ce6d8e047495a701dc7c5bd788add903f8986d523e3e20b98b733e421 \ + --hash=sha256:8db4c1b57507eef143a15a6884ca10f7c73876cdf5d51e713151c1236a0e68cf \ + --hash=sha256:aee678c8720623dc456fa20659af736241f575d79429a0e5e9cf88ae0605cc81 \ + --hash=sha256:bc56c2a1b0d15aa3eaa5a60c9f3f8e3e565303b465dbf57a1b730e7a2b9844e0 \ + --hash=sha256:bd1184ceb3f87651a67b2708d4c3338e9b10c5df903f2e3776b62303b26cb631 \ + --hash=sha256:d06016f7f8625a1825ba3732081d77c94589dca78b7a3fc072194851e88461a4 \ + --hash=sha256:d16bbddf0693323b8c6123dd804100241da461e41d6e332fb0ba6058f630f8c8 psycopg2-binary==2.9.7 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:00d8db270afb76f48a499f7bb8fa70297e66da67288471ca873db88382850bf4 \ --hash=sha256:024eaeb2a08c9a65cd5f94b31ace1ee3bb3f978cd4d079406aef85169ba01f08 \ @@ -1149,13 +1156,11 @@ pydeep2==0.5.1 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:2283893e25826b547dd1e5c71a010e86ddfd7270e2f2b8c90973c1d7984c7eb7 \ --hash=sha256:44ce447e3253a69d3393f3cc53e3a87a48fe3ff9861793736a7bc218a1b95d77 \ --hash=sha256:4bf00de2fe1918e4d698fe8195a5c0a3a0c3050a2e3e15583748cfd20b427153 \ - --hash=sha256:7809a1d6640bdbee68f075d53229d05229e11b4711f232728dd540f68e6483a4 \ --hash=sha256:7ca68f7d63e2ef510d410d20b223e8e97df41707fb50c4c526b6dd1d8698d9e6 \ --hash=sha256:a13fca9be89a9fa8d92a4f49d7b9191eef94555f8ddf030fb2be4c8c15ad618c \ --hash=sha256:add24d7aa0386b285fd3e99632719714efabeb13d7b03a015b7c64d1f588f815 \ --hash=sha256:c2063cbb053e5ce684cc45fff3e72c063b26aa85e41e6435cab0c658ad9e3e1e \ --hash=sha256:c65dc910d782fa2bc97e1b28a78d77c4bada037d14b63e3e75a1fa5918d642c5 \ - --hash=sha256:d1cb4757db97ac15ddf034c21cd6bab984f841586b6d53984e63c9a7803b2cd4 \ --hash=sha256:e14b310b820d895a7354be7fd025de874892df249cbfb3ad8a524459e1511fd8 \ --hash=sha256:ef00ca5681a2c4ad5dc744db5f8ae5406d3f13121b38d84cc58dfb8fce4c3dc2 \ --hash=sha256:f248e3161deb53d46a9368a7c164e36d83004faf2f11625d47a5cf23a6bdd2cb @@ -1339,9 +1344,7 @@ pytz==2021.1 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:83a4a90894bf38e243cf052c8b58f381bfe9a7a483f6a9cab140bc7f702ac4da \ --hash=sha256:eb10ce3e7736052ed3623d49975ce333bcd712c7bb19a58b9e2089d4057d0798 pyyaml==6.0.1 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:04ac92ad1925b2cff1db0cfebffb6ffc43457495c9b3c39d3fcae417d7125dc5 \ --hash=sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc \ - --hash=sha256:0d3304d8c0adc42be59c5f8a4d9e3d7379e6955ad754aa9d6ab7a398b59dd1df \ --hash=sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741 \ --hash=sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206 \ --hash=sha256:18aeb1bf9a78867dc38b259769503436b7c72f7a1f1f4c93ff9a17de54319b27 \ @@ -1349,10 +1352,7 @@ pyyaml==6.0.1 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62 \ --hash=sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98 \ --hash=sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696 \ - --hash=sha256:326c013efe8048858a6d312ddd31d56e468118ad4cdeda36c719bf5bb6192290 \ - --hash=sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9 \ --hash=sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d \ - --hash=sha256:49a183be227561de579b4a36efbb21b3eab9651dd81b1858589f796549873dd6 \ --hash=sha256:4fb147e7a67ef577a588a0e2c17b6db51dda102c71de36f8549b6816a96e1867 \ --hash=sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47 \ --hash=sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486 \ @@ -1360,15 +1360,11 @@ pyyaml==6.0.1 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:596106435fa6ad000c2991a98fa58eeb8656ef2325d7e158344fb33864ed87e3 \ --hash=sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007 \ --hash=sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938 \ - --hash=sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0 \ --hash=sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c \ --hash=sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735 \ --hash=sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d \ - --hash=sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28 \ - --hash=sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4 \ --hash=sha256:9046c58c4395dff28dd494285c82ba00b546adfc7ef001486fbf0324bc174fba \ --hash=sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8 \ - --hash=sha256:a08c6f0fe150303c1c6b71ebcd7213c2858041a7e01975da3a99aed1e7a378ef \ --hash=sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5 \ --hash=sha256:afd7e57eddb1a54f0f1a974bc4391af8bcce0b444685d936840f125cf046d5bd \ --hash=sha256:b1275ad35a5d18c62a7220633c913e1b42d44b46ee12554e5fd39c70a243d6a3 \ @@ -1381,9 +1377,7 @@ pyyaml==6.0.1 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43 \ --hash=sha256:c8098ddcc2a85b61647b2590f825f3db38891662cfc2fc776415143f599bb859 \ --hash=sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673 \ - --hash=sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54 \ --hash=sha256:d858aa552c999bc8a8d57426ed01e40bef403cd8ccdd0fc5f6f04a00414cac2a \ - --hash=sha256:e7d73685e87afe9f3b36c799222440d6cf362062f78be1013661b00c5c6f678b \ --hash=sha256:f003ed9ad21d6a4713f0a9b5a7a0a79e08dd0f221aff4525a2be4c346ee60aab \ --hash=sha256:f22ac1c3cac4dbc50079e965eba2c1058622631e526bd9afd45fedd49ba781fa \ --hash=sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c \ @@ -1625,48 +1619,27 @@ sqlalchemy==1.4.50 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:0b7dbe6369677a2bea68fe9812c6e4bbca06ebfa4b5cde257b2b0bf208709131 \ --hash=sha256:128a948bd40780667114b0297e2cc6d657b71effa942e0a368d8cc24293febb3 \ --hash=sha256:14b0cacdc8a4759a1e1bd47dc3ee3f5db997129eb091330beda1da5a0e9e5bd7 \ - --hash=sha256:1b9c4359d3198f341480e57494471201e736de459452caaacf6faa1aca852bd8 \ --hash=sha256:1fb9cb60e0f33040e4f4681e6658a7eb03b5cb4643284172f91410d8c493dace \ --hash=sha256:273505fcad22e58cc67329cefab2e436006fc68e3c5423056ee0513e6523268a \ --hash=sha256:2e70e0673d7d12fa6cd363453a0d22dac0d9978500aa6b46aa96e22690a55eab \ - --hash=sha256:324b1fdd50e960a93a231abb11d7e0f227989a371e3b9bd4f1259920f15d0304 \ --hash=sha256:34e1c5d9cd3e6bf3d1ce56971c62a40c06bfc02861728f368dcfec8aeedb2814 \ - --hash=sha256:35c7ed095a4b17dbc8813a2bfb38b5998318439da8e6db10a804df855e3a9e3a \ - --hash=sha256:35e4520f7c33c77f2636a1e860e4f8cafaac84b0b44abe5de4c6c8890b6aaa6d \ --hash=sha256:3b97ddf509fc21e10b09403b5219b06c5b558b27fc2453150274fa4e70707dbf \ --hash=sha256:3f6997da81114daef9203d30aabfa6b218a577fc2bd797c795c9c88c9eb78d49 \ - --hash=sha256:4be4da121d297ce81e1ba745a0a0521c6cf8704634d7b520e350dce5964c71ac \ - --hash=sha256:52e01d60b06f03b0a5fc303c8aada405729cbc91a56a64cead8cb7c0b9b13c1a \ - --hash=sha256:54138aa80d2dedd364f4e8220eef284c364d3270aaef621570aa2bd99902e2e8 \ - --hash=sha256:6b3df20fbbcbcd1c1d43f49ccf3eefb370499088ca251ded632b8cbaee1d497d \ - --hash=sha256:6c78e3fb4a58e900ec433b6b5f4efe1a0bf81bbb366ae7761c6e0051dd310ee3 \ - --hash=sha256:752f9df3dddbacb5f42d8405b2d5885675a93501eb5f86b88f2e47a839cf6337 \ - --hash=sha256:77fde9bf74f4659864c8e26ac08add8b084e479b9a18388e7db377afc391f926 \ - --hash=sha256:7b4396452273aedda447e5aebe68077aa7516abf3b3f48408793e771d696f397 \ --hash=sha256:82dd4131d88395df7c318eeeef367ec768c2a6fe5bd69423f7720c4edb79473c \ --hash=sha256:85292ff52ddf85a39367057c3d7968a12ee1fb84565331a36a8fead346f08796 \ - --hash=sha256:8a219688297ee5e887a93ce4679c87a60da4a5ce62b7cb4ee03d47e9e767f558 \ --hash=sha256:8a7a66297e46f85a04d68981917c75723e377d2e0599d15fbe7a56abed5e2d75 \ --hash=sha256:8b881ac07d15fb3e4f68c5a67aa5cdaf9eb8f09eb5545aaf4b0a5f5f4659be18 \ - --hash=sha256:8bdab03ff34fc91bfab005e96f672ae207d87e0ac7ee716d74e87e7046079d8b \ --hash=sha256:a3257a6e09626d32b28a0c5b4f1a97bced585e319cfa90b417f9ab0f6145c33c \ - --hash=sha256:a648770db002452703b729bdcf7d194e904aa4092b9a4d6ab185b48d13252f63 \ - --hash=sha256:a7c9b9dca64036008962dd6b0d9fdab2dfdbf96c82f74dbd5d86006d8d24a30f \ --hash=sha256:a9bddb60566dc45c57fd0a5e14dd2d9e5f106d2241e0a2dc0c1da144f9444516 \ --hash=sha256:bdb77e1789e7596b77fd48d99ec1d2108c3349abd20227eea0d48d3f8cf398d9 \ --hash=sha256:c1db0221cb26d66294f4ca18c533e427211673ab86c1fbaca8d6d9ff78654293 \ --hash=sha256:c4cb501d585aa74a0f86d0ea6263b9c5e1d1463f8f9071392477fd401bd3c7cc \ --hash=sha256:d00665725063692c42badfd521d0c4392e83c6c826795d38eb88fb108e5660e5 \ --hash=sha256:d0fed0f791d78e7767c2db28d34068649dfeea027b83ed18c45a423f741425cb \ - --hash=sha256:d55f7a33e8631e15af1b9e67c9387c894fedf6deb1a19f94be8731263c51d515 \ --hash=sha256:d69738d582e3a24125f0c246ed8d712b03bd21e148268421e4a4d09c34f521a5 \ --hash=sha256:db4db3c08ffbb18582f856545f058a7a5e4ab6f17f75795ca90b3c38ee0a8ba4 \ - --hash=sha256:df200762efbd672f7621b253721644642ff04a6ff957236e0e2fe56d9ca34d2c \ - --hash=sha256:e86c920b7d362cfa078c8b40e7765cbc34efb44c1007d7557920be9ddf138ec7 \ --hash=sha256:f1fcee5a2c859eecb4ed179edac5ffbc7c84ab09a5420219078ccc6edda45436 \ --hash=sha256:f2d526aeea1bd6a442abc7c9b4b00386fd70253b80d54a0930c0a216230a35be \ - --hash=sha256:f5b1fb2943d13aba17795a770d22a2ec2214fc65cff46c487790192dda3a3ee7 \ - --hash=sha256:fb9adc4c6752d62c6078c107d23327aa3023ef737938d0135ece8ffb67d07030 \ --hash=sha256:fbaf6643a604aa17e7a7afd74f665f9db882df5c297bdd86c38368f2c471f37d sqlparse==0.5.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:714d0a4932c059d16189f58ef5411ec2287a4360f17cdd0edd2d09d4c5087c93 \ From 2e98fce2f7fd4d63008a06f463851642cfc411bc Mon Sep 17 00:00:00 2001 From: doomedraven Date: Sat, 24 Aug 2024 08:44:05 +0200 Subject: [PATCH 009/121] Update rooter.py --- utils/rooter.py | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/utils/rooter.py b/utils/rooter.py index af88f1e123f..0ff502fdd8d 100644 --- a/utils/rooter.py +++ b/utils/rooter.py @@ -6,8 +6,6 @@ import argparse import errno import grp -import ipaddress -import psutil import json import logging.handlers import os @@ -92,7 +90,7 @@ def cleanup_rooter(): run_iptables("-N", "CAPE_REJECTED_SEGMENTS") run_iptables("-I", "FORWARD", "-j", "CAPE_REJECTED_SEGMENTS") run_iptables("-I", "FORWARD", "-j", "CAPE_ACCEPTED_SEGMENTS") - + def nic_available(interface): """Check if specified network interface is available.""" @@ -117,7 +115,7 @@ def rt_available(rt_table): return True except subprocess.CalledProcessError: return False - + def init_vrf(rt_table, dirty_line_dev): run(s.ip, "link", "add", "dirty-line", "type", "vrf", "table", rt_table) @@ -240,7 +238,7 @@ def forward_enable(src, dst, ipaddr, accept_segments=None, proto=None, ports=Non if not ports.isdigit(): log.debug("Invalid port entry: %s", ports) return False - + args = ["-I", "CAPE_ACCEPTED_SEGMENTS", "-i", src, "-o", dst, "--source", ipaddr] if accept_segments: args += ["--destination", accept_segments] @@ -275,7 +273,7 @@ def forward_disable(src, dst, ipaddr, accept_segments=None, proto=None, ports=No if not ports.isdigit(): log.debug("Invalid port entry: %s", ports) return False - + args = ["-D", "CAPE_ACCEPTED_SEGMENTS", "-i", src, "-o", dst, "--source", ipaddr] if accept_segments: args += ["--destination", accept_segments] @@ -283,7 +281,7 @@ def forward_disable(src, dst, ipaddr, accept_segments=None, proto=None, ports=No args += ["-p", proto, "-m", "multiport", "--dport", ports] args += ["-j", "ACCEPT"] run_iptables(*args) - + def forward_reject_enable(src, dst, ipaddr, reject_segments): """Enable forwarding a specific IP address from one interface into another From 2050b3c27f2a3df5c93805693da047d193d3bd42 Mon Sep 17 00:00:00 2001 From: doomedraven Date: Sat, 24 Aug 2024 08:55:02 +0200 Subject: [PATCH 010/121] Update cape2.sh --- installer/cape2.sh | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/installer/cape2.sh b/installer/cape2.sh index d892f4a779f..6ab438dc24e 100644 --- a/installer/cape2.sh +++ b/installer/cape2.sh @@ -1247,8 +1247,32 @@ function install_systemd() { if [ "$MONGO_ENABLE" -ge 1 ]; then cape_web_enable_string="cape-web" fi + systemctl enable cape cape-rooter cape-processor "$cape_web_enable_string" suricata systemctl restart cape cape-rooter cape-processor "$cape_web_enable_string" suricata + + if [ ! -f "/etc/sudoers.d/cape" ] ; then + cat > /etc/sudoers.d/cape << EOF +Cmnd_Alias CAPE_SVC = /usr/bin/systemctl stop cape, /usr/bin/systemctl start cape, /usr/bin/systemctl restart cape +Cmnd_Alias CAPE_WEB_SVC = /usr/bin/systemctl stop cape-web, /usr/bin/systemctl start cape-web, /usr/bin/systemctl restart cape-web +Cmnd_Alias CAPE_PROCESSING_SVC = /usr/bin/systemctl stop cape-processor, /usr/bin/systemctl start cape-processor, /usr/bin/systemctl restart cape-processor +Cmnd_Alias CAPE_ROOTER_SVC = /usr/bin/systemctl stop cape-rooter, /usr/bin/systemctl start cape-rooter, /usr/bin/systemctl restart cape-rooter +Cmnd_Alias SURICATA = /usr/bin/systemctl stop suricata, /usr/bin/systemctl start suricata, /usr/bin/systemctl restart suricata +Cmnd_Alias UWSGI = /usr/bin/systemctl stop uwsgi, /usr/bin/systemctl start uwsgi, /usr/bin/systemctl restart uwsgi + +# disttributed cape related +Cmnd_Alias CAPE_FSTAB_SVC = /usr/bin/systemctl stop cape-fstab, /usr/bin/systemctl start cape-fstab, /usr/bin/systemctl restart cape-fstab + +%${USER} ALL=CAPE_SVC +%${USER} ALL=CAPE_WEB_SVC +%${USER} ALL=CAPE_PROCESSING_SVC +%${USER} ALL=CAPE_ROOTER_SVC +%${USER} ALL=SURICATA +%${USER} ALL=UWSGI + +%cape ALL=CAPE_FSTAB_SVC +EOF + fi } @@ -1263,6 +1287,7 @@ function install_prometheus_grafana() { sudo dpkg -i grafana_"$grafana_version"_amd64.deb systemctl enable grafana + cat << EOL Edit grafana config to listen on correct interface, default localhost, then systemctl start grafana From a4ef19e7a9dcda0ff47a9b173f0d3b689d93d8d5 Mon Sep 17 00:00:00 2001 From: enzo <7831008+enzok@users.noreply.github.com> Date: Tue, 27 Aug 2024 13:34:29 -0400 Subject: [PATCH 011/121] Only import enabled auxiliary modules (#2294) * Only start enabled auxiliary modules * Only import enabled modules --- analyzer/windows/analyzer.py | 32 ++++++++++---------------------- 1 file changed, 10 insertions(+), 22 deletions(-) diff --git a/analyzer/windows/analyzer.py b/analyzer/windows/analyzer.py index dd10340f135..a389e0428a1 100644 --- a/analyzer/windows/analyzer.py +++ b/analyzer/windows/analyzer.py @@ -497,46 +497,34 @@ def run(self): Auxiliary() prefix = f"{auxiliary.__name__}." - # disable_screens = True - # if self.options.get("disable_screens") == "0": - # disable_screens = False - for _, name, _ in pkgutil.iter_modules(auxiliary.__path__, prefix): try: - log.debug('Importing auxiliary module "%s"...', name) - __import__(name, globals(), locals(), ["dummy"]) - # log.debug('Imported auxiliary module "%s"', name) + mod_name = name.split(".")[-1] + if hasattr(self.config, mod_name) and getattr(self.config, mod_name, False): + log.debug('Importing auxiliary module "%s"...', name) + __import__(name, globals(), locals(), ["dummy"]) + # log.debug('Imported auxiliary module "%s"', name) except ImportError as e: log.warning('Unable to import the auxiliary module "%s": %s', name, e) + # Walk through the available auxiliary modules. aux_modules = [] for module in sorted(Auxiliary.__subclasses__(), key=lambda x: x.start_priority, reverse=True): - # Try to start the auxiliary module. - # if module.__name__ == "Screenshots" and disable_screens: - # continue try: aux = module(self.options, self.config) log.debug('Initialized auxiliary module "%s"', module.__name__) aux_modules.append(aux) - - # The following commented out code causes the monitor to not upload logs. - # If the auxiliary module is not enabled, we shouldn't start it - # if hasattr(aux, "enabled") and not getattr(aux, "enabled", False): - # log.debug('Auxiliary module "%s" is disabled.', module.__name__) - # # We continue so that the module is not added to AUX_ENABLED - # continue - # else: - log.debug('Trying to start auxiliary module "%s"...', module.__name__) + log.debug('Trying to start auxiliary module "%s"...', module.__module__) aux.start() except (NotImplementedError, AttributeError) as e: log.warning("Auxiliary module %s was not implemented: %s", module.__name__, e) except Exception as e: - log.warning("Cannot execute auxiliary module %s: %s", module.__name__, e) + log.warning("Cannot execute auxiliary module %s: %s", module.__module__, e) else: - log.debug("Started auxiliary module %s", module.__name__) + log.debug("Started auxiliary module %s", module.__module__) AUX_ENABLED.append(aux) - + """ # Inform zer0m0n of the ResultServer address. zer0m0n.resultserver(self.config.ip, self.config.port) From d605730cd538fc8a46571a82126ea7e21da7873c Mon Sep 17 00:00:00 2001 From: enzo <7831008+enzok@users.noreply.github.com> Date: Tue, 27 Aug 2024 15:39:36 -0400 Subject: [PATCH 012/121] Support pcap_ng captures (#2296) --- modules/processing/network.py | 34 +++++++++++++++++++++++++++++++--- 1 file changed, 31 insertions(+), 3 deletions(-) diff --git a/modules/processing/network.py b/modules/processing/network.py index b5de5331994..113ca0fbfd7 100644 --- a/modules/processing/network.py +++ b/modules/processing/network.py @@ -78,6 +78,7 @@ sys.path.append(CUCKOO_ROOT) TLS_HANDSHAKE = 22 +PCAP_TYPE = None Keyed = namedtuple("Keyed", ["key", "obj"]) Packet = namedtuple("Packet", ["raw", "ts"]) @@ -736,7 +737,12 @@ def run(self): return self.results try: - pcap = dpkt.pcap.Reader(file) + if PCAP_TYPE == "pcap": + pcap = dpkt.pcap.Reader(file) + elif PCAP_TYPE == "pcapng": + pcap = dpkt.pcapng.Reader(file) + else: + return self.results except dpkt.dpkt.NeedData: log.error('Unable to read PCAP file at path "%s"', self.filepath) return self.results @@ -1087,6 +1093,8 @@ def _import_ja3_fprints(self): return ja3_fprints def run(self): + global PCAP_TYPE + PCAP_TYPE = check_pcap_file_type(self.pcap_path) self.key = "network" self.ja3_file = self.options.get("ja3_file", os.path.join(CUCKOO_ROOT, "data", "ja3", "ja3fingerprint.json")) if not IS_DPKT: @@ -1225,14 +1233,20 @@ def __init__(self, path, linktype=1): def write(self, p=None): if not self.fileobj: self.fileobj = open(self.name, "wb") - self.fd = dpkt.pcap.Writer(self.fileobj, linktype=self.linktype) + if PCAP_TYPE == "pcap": + self.fd = dpkt.pcap.Writer(self.fileobj, linktype=self.linktype) + elif PCAP_TYPE == "pcapng": + self.fd = dpkt.pcapng.Writer(self.fileobj, linktype=self.linktype) if p: self.fd.writepkt(p.raw, p.ts) def __iter__(self): if not self.fileobj: self.fileobj = open(self.name, "rb") - self.fd = dpkt.pcap.Reader(self.fileobj) + if PCAP_TYPE == "pcap": + self.fd = dpkt.pcap.Reader(self.fileobj) + elif PCAP_TYPE == "pcapng": + self.fd = dpkt.pcapng.Reader(self.fileobj) self.fditer = iter(self.fd) self.linktype = self.fd.datalink() return self @@ -1338,3 +1352,17 @@ def packets_for_stream(fobj, offset): fobj.seek(offset) for p in next_connection_packets(pcapiter, linktype=pcap.datalink()): yield p + + +def check_pcap_file_type(filepath): + with open(filepath, "rb") as fd: + magic_number = fd.read(4) + fd.seek(0) + magic_number = int.from_bytes(magic_number, byteorder='little') + + if magic_number in (0xa1b2c3d4, 0xd4c3b2a1): + return "pcap" + elif magic_number == 0x0a0d0d0a: + return "pcapng" + else: + return From 18f4c4751b2c268f2c3ca7599fcfb36c26bd5618 Mon Sep 17 00:00:00 2001 From: enzo <7831008+enzok@users.noreply.github.com> Date: Tue, 24 Sep 2024 14:44:41 -0400 Subject: [PATCH 013/121] Modify aux module config names (#2327) --- analyzer/windows/analyzer.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/analyzer/windows/analyzer.py b/analyzer/windows/analyzer.py index a389e0428a1..5627ccbb27b 100644 --- a/analyzer/windows/analyzer.py +++ b/analyzer/windows/analyzer.py @@ -496,10 +496,13 @@ def run(self): # Initialize Auxiliary modules Auxiliary() prefix = f"{auxiliary.__name__}." + windows_modules = ["human", "screenshots", "sysmon"] for _, name, _ in pkgutil.iter_modules(auxiliary.__path__, prefix): try: mod_name = name.split(".")[-1] + if mod_name in windows_modules: + mod_name += "_windows" if hasattr(self.config, mod_name) and getattr(self.config, mod_name, False): log.debug('Importing auxiliary module "%s"...', name) __import__(name, globals(), locals(), ["dummy"]) From 242681d9289b323697d3e591d46e69ea4cf50e7b Mon Sep 17 00:00:00 2001 From: doomedraven Date: Tue, 24 Sep 2024 21:41:34 +0200 Subject: [PATCH 014/121] fix --- modules/processing/network.py | 6 +++--- tests/data | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/modules/processing/network.py b/modules/processing/network.py index c90d4f21f1b..cc36b788eef 100644 --- a/modules/processing/network.py +++ b/modules/processing/network.py @@ -1369,11 +1369,11 @@ def check_pcap_file_type(filepath): with open(filepath, "rb") as fd: magic_number = fd.read(4) fd.seek(0) - magic_number = int.from_bytes(magic_number, byteorder='little') + magic_number = int.from_bytes(magic_number, byteorder="little") - if magic_number in (0xa1b2c3d4, 0xd4c3b2a1): + if magic_number in (0xA1B2C3D4, 0xD4C3B2A1): return "pcap" - elif magic_number == 0x0a0d0d0a: + elif magic_number == 0x0A0D0D0A: return "pcapng" else: return diff --git a/tests/data b/tests/data index b394a00ba36..7c38432d1cc 160000 --- a/tests/data +++ b/tests/data @@ -1 +1 @@ -Subproject commit b394a00ba3649afc69e7f22ad845a3a8a659200e +Subproject commit 7c38432d1cceb6231766227ef45b1321315d3aaf From c56fd026d869461b203b69c8bba69f5f5432b185 Mon Sep 17 00:00:00 2001 From: doomedraven Date: Fri, 27 Sep 2024 11:52:29 +0200 Subject: [PATCH 015/121] Update analyzer.py --- analyzer/windows/analyzer.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/analyzer/windows/analyzer.py b/analyzer/windows/analyzer.py index 7061593d247..8444dd9aaeb 100644 --- a/analyzer/windows/analyzer.py +++ b/analyzer/windows/analyzer.py @@ -496,15 +496,15 @@ def run(self): # Initialize Auxiliary modules Auxiliary() prefix = f"{auxiliary.__name__}." - windows_modules = ["human", "screenshots", "sysmon"] + windows_modules = ("human", "screenshots", "sysmon") for _, name, _ in pkgutil.iter_modules(auxiliary.__path__, prefix): try: mod_name = name.split(".")[-1] if mod_name in windows_modules: mod_name += "_windows" - if hasattr(self.config, mod_name) and getattr(self.config, mod_name, False): - # log.debug('Imported auxiliary module "%s"', name) + # if hasattr(self.config, mod_name) and getattr(self.config, mod_name, False): + # log.debug('Imported auxiliary module "%s"', name) except ImportError as e: log.warning('Unable to import the auxiliary module "%s": %s', name, e) From 3003c89e44189b6e5b374addc473542dd174dbb1 Mon Sep 17 00:00:00 2001 From: cccs-mog <117194682+cccs-mog@users.noreply.github.com> Date: Sun, 29 Sep 2024 03:25:41 -0400 Subject: [PATCH 016/121] Pending tasks timeout (#2332) --- conf/default/cuckoo.conf.default | 5 +++++ lib/cuckoo/core/database.py | 21 ++++++++++++++++++--- lib/cuckoo/core/scheduler.py | 8 ++++++++ tests/test_analysis_manager.py | 3 +++ 4 files changed, 34 insertions(+), 3 deletions(-) diff --git a/conf/default/cuckoo.conf.default b/conf/default/cuckoo.conf.default index afb2098afab..b89eaeae4ca 100644 --- a/conf/default/cuckoo.conf.default +++ b/conf/default/cuckoo.conf.default @@ -33,6 +33,11 @@ scaling_semaphore = off # A configurable wait time between updating the limit value of the scaling bounded semaphore scaling_semaphore_update_timer = 10 +# Specify a timeout for tasks, useful if you are bound to timely reports awaited by users +task_timeout = off +task_pending_timeout = 0 +task_timeout_scan_interval = 30 + # Enable creation of memory dump of the analysis machine before shutting # down. Even if turned off, this functionality can also be enabled at # submission. Currently available for: VirtualBox and libvirt modules (KVM). diff --git a/lib/cuckoo/core/database.py b/lib/cuckoo/core/database.py index eb643b56d75..8a8c5993b68 100644 --- a/lib/cuckoo/core/database.py +++ b/lib/cuckoo/core/database.py @@ -169,8 +169,8 @@ tasks_tags = Table( "tasks_tags", Base.metadata, - Column("task_id", Integer, ForeignKey("tasks.id")), - Column("tag_id", Integer, ForeignKey("tags.id")), + Column("task_id", Integer, ForeignKey("tasks.id", ondelete='cascade')), + Column("tag_id", Integer, ForeignKey("tags.id", ondelete='cascade')), ) @@ -268,7 +268,7 @@ class Guest(Base): manager = Column(String(255), nullable=False) started_on = Column(DateTime(timezone=False), default=datetime.now, nullable=False) shutdown_on = Column(DateTime(timezone=False), nullable=True) - task_id = Column(Integer, ForeignKey("tasks.id"), nullable=False, unique=True) + task_id = Column(Integer, ForeignKey("tasks.id", ondelete='cascade'), nullable=False, unique=True) def __repr__(self): return f"" @@ -2078,6 +2078,21 @@ def list_tasks( return tasks + def check_tasks_timeout(self, timeout): + """Find tasks which were added_on more than timeout ago and clean + """ + tasks: List[Task] = [] + ids_to_delete = [] + if timeout == 0: + return + search = self.session.query(Task).filter(Task.status == TASK_PENDING).order_by(Task.added_on.desc()) + tasks = search.all() + for task in tasks: + if task.added_on + timedelta(seconds = timeout) < datetime.now(): + ids_to_delete.append(task.id) + if len(ids_to_delete) > 0: + self.session.query(Task).filter(Task.id.in_(ids_to_delete)).delete(synchronize_session=False) + def minmax_tasks(self): """Find tasks minimum and maximum @return: unix timestamps of minimum and maximum diff --git a/lib/cuckoo/core/scheduler.py b/lib/cuckoo/core/scheduler.py index 8698ec52a86..3831c4a55b3 100644 --- a/lib/cuckoo/core/scheduler.py +++ b/lib/cuckoo/core/scheduler.py @@ -64,6 +64,8 @@ def __init__(self, maxcount=0): self.analysis_threads: List[AnalysisManager] = [] self.analyzing_categories, categories_need_VM = load_categories() self.machinery_manager = MachineryManager() if categories_need_VM else None + if self.cfg.cuckoo.get("task_timeout", False): + self.next_timeout_time = time.time() + self.cfg.cuckoo.get("task_timeout_scan_interval", 30) log.info("Creating scheduler with max_analysis_count=%s", self.max_analysis_count or "unlimited") @property @@ -98,6 +100,12 @@ def do_main_loop_work(self, error_queue: queue.Queue) -> SchedulerCycleDelay: if self.is_short_on_disk_space(): return SchedulerCycleDelay.LOW_DISK_SPACE + if self.cfg.cuckoo.get("task_timeout", False): + if self.next_timeout_time < time.time(): + self.next_timeout_time = time.time() + self.cfg.cuckoo.get("task_timeout_scan_interval", 30) + with self.db.session.begin(): + self.db.check_tasks_timeout(self.cfg.cuckoo.get("task_pending_timeout", 0)) + analysis_manager: Optional[AnalysisManager] = None with self.db.session.begin(): max_machines_reached = False diff --git a/tests/test_analysis_manager.py b/tests/test_analysis_manager.py index 064d7173d00..c9120e06420 100644 --- a/tests/test_analysis_manager.py +++ b/tests/test_analysis_manager.py @@ -129,6 +129,9 @@ def test_init(self, task: Task): "sanitize_to_len": 24, "scaling_semaphore": False, "scaling_semaphore_update_timer": 10, + "task_pending_timeout": 0, + "task_timeout": False, + "task_timeout_scan_interval": 30, "freespace_processing": 15000, "periodic_log": False, "fail_unserviceable": True, From a386155ad8ebb145e3207f9699d4e9929d2f1373 Mon Sep 17 00:00:00 2001 From: YungBinary <93540406+YungBinary@users.noreply.github.com> Date: Wed, 30 Oct 2024 08:30:03 +0000 Subject: [PATCH 017/121] Add Snake Keylogger config extractor (#2379) * Snake Keylogger config extractor * Fix unused imports * Add test * Fix --- modules/processing/parsers/CAPE/Snake.py | 153 +++++++++++++++++++++++ tests_parsers/test_snake.py | 11 ++ 2 files changed, 164 insertions(+) create mode 100644 modules/processing/parsers/CAPE/Snake.py create mode 100644 tests_parsers/test_snake.py diff --git a/modules/processing/parsers/CAPE/Snake.py b/modules/processing/parsers/CAPE/Snake.py new file mode 100644 index 00000000000..8d7deb545a8 --- /dev/null +++ b/modules/processing/parsers/CAPE/Snake.py @@ -0,0 +1,153 @@ +import base64 +import re +import hashlib +import dnfile +import logging +import traceback + +try: + from Cryptodome.Cipher import DES + from Cryptodome.Util.Padding import unpad +except ModuleNotFoundError: + raise ModuleNotFoundError("Please run: pip3 install pycryptodomex") + +log = logging.getLogger(__name__) +log.setLevel(logging.INFO) + +def is_base64(s): + pattern = re.compile("^([A-Za-z0-9+/]{4})*([A-Za-z0-9+/]{4}|[A-Za-z0-9+/]{3}=|[A-Za-z0-9+/]{2}==)$") + if not s or len(s) < 1: + return False + else: + return pattern.match(s) + +def pad(text): + n = len(text) % 8 + return text + (b' ' * n) + +def md5(string: bytes) -> bytes: + return bytes.fromhex(hashlib.md5(string).hexdigest()) + +def handle_plain(dotnet_file, c2_type, user_strings): + user_strings_list = list(user_strings.values()) + if c2_type == "Telegram": + token = dotnet_file.net.user_strings.get(user_strings_list[15]).value.__str__() + chat_id = dotnet_file.net.user_strings.get(user_strings_list[16]).value.__str__() + return {"Type": "Telegram", "C2": f"https://api.telegram.org/bot{token}/sendMessage?chat_id={chat_id}"} + elif c2_type == "SMTP": + smtp_from = dotnet_file.net.user_strings.get(user_strings_list[7]).value.__str__() + smtp_password = dotnet_file.net.user_strings.get(user_strings_list[8]).value.__str__() + smtp_host = dotnet_file.net.user_strings.get(user_strings_list[9]).value.__str__() + smtp_to = dotnet_file.net.user_strings.get(user_strings_list[10]).value.__str__() + smtp_port = dotnet_file.net.user_strings.get(user_strings_list[11]).value.__str__() + return {"Type": "SMTP", "Host": smtp_host, "Port": smtp_port, "From Address": smtp_from, "To Address": smtp_to, "Password": smtp_password} + elif c2_type == "FTP": + ftp_username = dotnet_file.net.user_strings.get(user_strings_list[12]).value.__str__() + ftp_password = dotnet_file.net.user_strings.get(user_strings_list[13]).value.__str__() + ftp_host = dotnet_file.net.user_strings.get(user_strings_list[14]).value.__str__() + return {"Type": "FTP", "Host": ftp_host, "Username": ftp_username, "Password": ftp_password} + +def handle_encrypted(dotnet_file, data, c2_type, user_strings): + # Match decrypt string pattern + decrypt_string_pattern = re.compile( + Rb"""(?x) + \x72(...)\x70 + \x7E(...)\x04 + \x28...\x06 + \x80...\x04 + """ + ) + + config_dict = None + decrypted_strings = [] + + matches2 = decrypt_string_pattern.findall(data) + for match in matches2: + string_index = int.from_bytes(match[0], "little") + user_string = dotnet_file.net.user_strings.get(string_index).value + # Skip user strings that are empty/not base64 + if user_string == "Yx74dJ0TP3M=" or not is_base64(user_string): + continue + field_row_index = int.from_bytes(match[1], "little") + field_name = dotnet_file.net.mdtables.Field.get_with_row_index(field_row_index).Name.__str__() + key_index = user_strings[field_name] + key_str = dotnet_file.net.user_strings.get(key_index).value.__str__() + key = md5(key_str.encode())[:8] + des = DES.new(key, DES.MODE_ECB) + + decoded_str = base64.b64decode(user_string) + padded_str = pad(decoded_str) + decrypted_text = des.decrypt(padded_str) + plaintext_bytes = unpad(decrypted_text, DES.block_size) + plaintext = plaintext_bytes.decode() + decrypted_strings.append(plaintext) + + if decrypted_strings: + if c2_type == "Telegram": + token, chat_id = decrypted_strings + config_dict = {"Type": "Telegram", "C2": f"https://api.telegram.org/bot{token}/sendMessage?chat_id={chat_id}"} + elif c2_type == "SMTP": + smtp_from, smtp_password, smtp_host, smtp_to, smtp_port = decrypted_strings + config_dict = {"Type": "SMTP", "Host": smtp_host, "Port": smtp_port, "From Address": smtp_from, "To Address": smtp_to, "Password": smtp_password} + elif c2_type == "FTP": + ftp_username, ftp_password, ftp_host = decrypted_strings + config_dict = {"Type": "FTP", "Host": ftp_host, "Username": ftp_username, "Password": ftp_password} + return config_dict + +def extract_config(data): + + try: + dotnet_file = dnfile.dnPE(data=data) + except Exception as e: + log.debug(f"Exception when attempting to parse .NET file: {e}") + log.debug(traceback.format_exc()) + + # ldstr, stsfld + static_strings = re.compile( + Rb"""(?x) + \x72(...)\x70 + \x80(...)\x04 + """ + ) + + # Get user strings and C2 type + user_strings = {} + c2_type = None + matches = static_strings.findall(data) + for match in matches: + try: + string_index = int.from_bytes(match[0], "little") + string_value = dotnet_file.net.user_strings.get(string_index).value.__str__() + field_index = int.from_bytes(match[1], "little") + field_name = dotnet_file.net.mdtables.Field.get_with_row_index(field_index).Name.__str__() + if string_value == '$%TelegramDv$': + c2_type = 'Telegram' + + elif string_value == '$%SMTPDV$': + c2_type = 'SMTP' + + elif string_value == '%FTPDV$': + c2_type = 'FTP' + else: + user_strings[field_name] = string_index + except Exception as e: + log.debug(f"There was an exception parsing user strings: {e}") + log.debug(traceback.format_exc()) + + if c2_type is None: + raise ValueError("Could not identify C2 type.") + + # Handle encrypted strings + config_dict = handle_encrypted(dotnet_file, data, c2_type, user_strings) + if config_dict is None: + # Handle plain strings + config_dict = handle_plain(dotnet_file, c2_type, user_strings) + + return config_dict + + +if __name__ == "__main__": + import sys + + with open(sys.argv[1], "rb") as f: + print(extract_config(f.read())) diff --git a/tests_parsers/test_snake.py b/tests_parsers/test_snake.py new file mode 100644 index 00000000000..9558d6d26a8 --- /dev/null +++ b/tests_parsers/test_snake.py @@ -0,0 +1,11 @@ +# Copyright (C) 2010-2015 Cuckoo Foundation. +# This file is part of Cuckoo Sandbox - http://www.cuckoosandbox.org +# See the file 'docs/LICENSE' for copying permission. + +from modules.processing.parsers.CAPE.Snake import extract_config + + +def test_snake(): + with open("tests/data/malware/7b81c12fb7db9f0c317f36022ecac9faa45f5efefe24085c339c43db8b963ae2", "rb") as data: + conf = extract_config(data.read()) + assert conf == {'Type': 'Telegram', 'C2': 'https://api.telegram.org/bot7952998151:AAFh98iY7kaOlHAR0qftD3ZcqGbQm0TXbBY/sendMessage?chat_id=5692813672'} From 986bd4feb6dd169922a1f716ba452c3472d64c60 Mon Sep 17 00:00:00 2001 From: GitHub Actions Date: Wed, 30 Oct 2024 08:30:57 +0000 Subject: [PATCH 018/121] style: Automatic code formatting --- modules/processing/parsers/CAPE/Snake.py | 47 +++++++++++++++++------- tests_parsers/test_snake.py | 5 ++- 2 files changed, 38 insertions(+), 14 deletions(-) diff --git a/modules/processing/parsers/CAPE/Snake.py b/modules/processing/parsers/CAPE/Snake.py index 8d7deb545a8..50356034693 100644 --- a/modules/processing/parsers/CAPE/Snake.py +++ b/modules/processing/parsers/CAPE/Snake.py @@ -1,10 +1,11 @@ import base64 -import re import hashlib -import dnfile import logging +import re import traceback +import dnfile + try: from Cryptodome.Cipher import DES from Cryptodome.Util.Padding import unpad @@ -14,6 +15,7 @@ log = logging.getLogger(__name__) log.setLevel(logging.INFO) + def is_base64(s): pattern = re.compile("^([A-Za-z0-9+/]{4})*([A-Za-z0-9+/]{4}|[A-Za-z0-9+/]{3}=|[A-Za-z0-9+/]{2}==)$") if not s or len(s) < 1: @@ -21,13 +23,16 @@ def is_base64(s): else: return pattern.match(s) + def pad(text): n = len(text) % 8 - return text + (b' ' * n) + return text + (b" " * n) + def md5(string: bytes) -> bytes: return bytes.fromhex(hashlib.md5(string).hexdigest()) + def handle_plain(dotnet_file, c2_type, user_strings): user_strings_list = list(user_strings.values()) if c2_type == "Telegram": @@ -40,13 +45,21 @@ def handle_plain(dotnet_file, c2_type, user_strings): smtp_host = dotnet_file.net.user_strings.get(user_strings_list[9]).value.__str__() smtp_to = dotnet_file.net.user_strings.get(user_strings_list[10]).value.__str__() smtp_port = dotnet_file.net.user_strings.get(user_strings_list[11]).value.__str__() - return {"Type": "SMTP", "Host": smtp_host, "Port": smtp_port, "From Address": smtp_from, "To Address": smtp_to, "Password": smtp_password} + return { + "Type": "SMTP", + "Host": smtp_host, + "Port": smtp_port, + "From Address": smtp_from, + "To Address": smtp_to, + "Password": smtp_password, + } elif c2_type == "FTP": ftp_username = dotnet_file.net.user_strings.get(user_strings_list[12]).value.__str__() ftp_password = dotnet_file.net.user_strings.get(user_strings_list[13]).value.__str__() ftp_host = dotnet_file.net.user_strings.get(user_strings_list[14]).value.__str__() return {"Type": "FTP", "Host": ftp_host, "Username": ftp_username, "Password": ftp_password} + def handle_encrypted(dotnet_file, data, c2_type, user_strings): # Match decrypt string pattern decrypt_string_pattern = re.compile( @@ -88,12 +101,20 @@ def handle_encrypted(dotnet_file, data, c2_type, user_strings): config_dict = {"Type": "Telegram", "C2": f"https://api.telegram.org/bot{token}/sendMessage?chat_id={chat_id}"} elif c2_type == "SMTP": smtp_from, smtp_password, smtp_host, smtp_to, smtp_port = decrypted_strings - config_dict = {"Type": "SMTP", "Host": smtp_host, "Port": smtp_port, "From Address": smtp_from, "To Address": smtp_to, "Password": smtp_password} + config_dict = { + "Type": "SMTP", + "Host": smtp_host, + "Port": smtp_port, + "From Address": smtp_from, + "To Address": smtp_to, + "Password": smtp_password, + } elif c2_type == "FTP": ftp_username, ftp_password, ftp_host = decrypted_strings config_dict = {"Type": "FTP", "Host": ftp_host, "Username": ftp_username, "Password": ftp_password} return config_dict + def extract_config(data): try: @@ -120,14 +141,14 @@ def extract_config(data): string_value = dotnet_file.net.user_strings.get(string_index).value.__str__() field_index = int.from_bytes(match[1], "little") field_name = dotnet_file.net.mdtables.Field.get_with_row_index(field_index).Name.__str__() - if string_value == '$%TelegramDv$': - c2_type = 'Telegram' - - elif string_value == '$%SMTPDV$': - c2_type = 'SMTP' - - elif string_value == '%FTPDV$': - c2_type = 'FTP' + if string_value == "$%TelegramDv$": + c2_type = "Telegram" + + elif string_value == "$%SMTPDV$": + c2_type = "SMTP" + + elif string_value == "%FTPDV$": + c2_type = "FTP" else: user_strings[field_name] = string_index except Exception as e: diff --git a/tests_parsers/test_snake.py b/tests_parsers/test_snake.py index 9558d6d26a8..489418eca86 100644 --- a/tests_parsers/test_snake.py +++ b/tests_parsers/test_snake.py @@ -8,4 +8,7 @@ def test_snake(): with open("tests/data/malware/7b81c12fb7db9f0c317f36022ecac9faa45f5efefe24085c339c43db8b963ae2", "rb") as data: conf = extract_config(data.read()) - assert conf == {'Type': 'Telegram', 'C2': 'https://api.telegram.org/bot7952998151:AAFh98iY7kaOlHAR0qftD3ZcqGbQm0TXbBY/sendMessage?chat_id=5692813672'} + assert conf == { + "Type": "Telegram", + "C2": "https://api.telegram.org/bot7952998151:AAFh98iY7kaOlHAR0qftD3ZcqGbQm0TXbBY/sendMessage?chat_id=5692813672", + } From c7a857bcfe17af3d372317e82b03adbfcb2c9890 Mon Sep 17 00:00:00 2001 From: doomedraven Date: Wed, 30 Oct 2024 09:32:51 +0100 Subject: [PATCH 019/121] Update cape2.sh --- installer/cape2.sh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/installer/cape2.sh b/installer/cape2.sh index c674fd4a3f1..f514aa899a4 100644 --- a/installer/cape2.sh +++ b/installer/cape2.sh @@ -931,7 +931,9 @@ function dependencies() { apt-get install uthash-dev libconfig-dev libarchive-dev libtool autoconf automake privoxy software-properties-common wkhtmltopdf xvfb xfonts-100dpi tcpdump libcap2-bin wireshark-common -y apt-get install python3-pil subversion uwsgi uwsgi-plugin-python3 python3-pyelftools git curl -y apt-get install openvpn wireguard -y - apt-get install python3-poetry crudini -y + apt-get install crudini -y + # APT poetry is ultra outdated + curl -sSL https://install.python-poetry.org | python3 - apt-get install locate # used by extra/libvirt_installer.sh # de4dot selfextraction From 9500546110faa57a1b6fadd3fced6d78b038851c Mon Sep 17 00:00:00 2001 From: David Santos <44490090+dsecuma@users.noreply.github.com> Date: Wed, 30 Oct 2024 09:35:34 +0100 Subject: [PATCH 020/121] get HAR from api (#2381) --- conf/default/api.conf.default | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/conf/default/api.conf.default b/conf/default/api.conf.default index f1a6828d768..96e249df910 100644 --- a/conf/default/api.conf.default +++ b/conf/default/api.conf.default @@ -252,6 +252,10 @@ compress = no rps = 1/s rpm = 2/m +# Pull a HAR file from a specific task with mitmdump enabled +[taskmitmdump] +enabled = no + # Download a sample from a specific Task ID. [sampledl] enabled = no From e112deb3b352576910e0e82be7b59486ffaafed2 Mon Sep 17 00:00:00 2001 From: doomedraven Date: Wed, 30 Oct 2024 14:08:51 +0100 Subject: [PATCH 021/121] maco optional (#2380) * maco optional * Update poetry.lock --- poetry.lock | 7 +- pyproject.toml | 2 + tests_parsers/test_agenttesla.py | 54 +++--- tests_parsers/test_asyncrat.py | 43 +++-- tests_parsers/test_aurorastealer.py | 33 ++-- tests_parsers/test_blackdropper.py | 30 ++-- tests_parsers/test_bumblebee.py | 23 ++- tests_parsers/test_carbanak.py | 17 +- tests_parsers/test_cobaltstrikebeacon.py | 126 +++++++------- tests_parsers/test_darkgate.py | 17 +- tests_parsers/test_icedid.py | 19 +- tests_parsers/test_koiloader.py | 24 +-- tests_parsers/test_latrodectus.py | 211 ++++++++++++----------- tests_parsers/test_lumma.py | 61 ++++--- tests_parsers/test_nanocore.py | 119 +++++++------ tests_parsers/test_njrat.py | 25 +-- tests_parsers/test_oyster.py | 29 ++-- tests_parsers/test_pikabot.py | 169 +++++++++--------- tests_parsers/test_quickbind.py | 30 ++-- tests_parsers/test_redline.py | 28 +-- tests_parsers/test_smokeloader.py | 18 +- tests_parsers/test_sparkrat.py | 33 ++-- tests_parsers/test_zloader.py | 30 ++-- 23 files changed, 630 insertions(+), 518 deletions(-) diff --git a/poetry.lock b/poetry.lock index c47b98b49da..9aeb10ad277 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.8.3 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.8.4 and should not be changed by hand. [[package]] name = "alembic" @@ -4609,7 +4609,10 @@ docs = ["Sphinx", "repoze.sphinx.autointerface", "sphinx-rtd-theme"] test = ["coverage (>=5.0.3)", "zope.event", "zope.testing"] testing = ["coverage (>=5.0.3)", "zope.event", "zope.testing"] +[extras] +maco = ["maco"] + [metadata] lock-version = "2.0" python-versions = ">=3.10, <4.0" -content-hash = "d8e5cf52c678477800f15c8cbc7b3aa9a888a98e0cab0c8f4c3e18dd7b30e705" +content-hash = "ab3f807dcdc7fa1fb2098ee2222602ffde65894297ca6b4c3629f2528d584d09" diff --git a/pyproject.toml b/pyproject.toml index 418cbb9aff9..43be4a45a58 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -92,6 +92,8 @@ setproctitle = "1.3.2" # tmp dependency to fix vuln certifi = "2024.7.4" +[tool.poetry.extras] +maco = ["maco"] [tool.poetry.dev-dependencies] black = "^24.3.0" diff --git a/tests_parsers/test_agenttesla.py b/tests_parsers/test_agenttesla.py index 5390edb9b70..37050c3328e 100644 --- a/tests_parsers/test_agenttesla.py +++ b/tests_parsers/test_agenttesla.py @@ -1,5 +1,10 @@ from modules.processing.parsers.CAPE.AgentTesla import extract_config -from modules.processing.parsers.MACO.AgentTesla import convert_to_MACO + +from contextlib import suppress +HAVE_MACO = False +with suppress(ImportError): + from modules.processing.parsers.MACO.AgentTesla import convert_to_MACO + HAVE_MACO = True def test_agenttesla(): @@ -16,26 +21,27 @@ def test_agenttesla(): "ExternalIPCheckServices": ["http://ip-api.com/line/?fields=hosting"], } - assert convert_to_MACO(conf).model_dump(exclude_defaults=True, exclude_none=True) == { - "family": "AgentTesla", - "other": { - "Protocol": "SMTP", - "C2": "mail.guestequipment.com.au", - "Username": "sendlog@guestequipment.com.au", - "Password": "Clone89!", - "EmailTo": "info@marethon.com", - "Persistence_Filename": "newfile.exe", - "ExternalIPCheckServices": ["http://ip-api.com/line/?fields=hosting"], - }, - "smtp": [ - { - "username": "sendlog@guestequipment.com.au", - "password": "Clone89!", - "hostname": "mail.guestequipment.com.au", - "mail_to": ["info@marethon.com"], - "usage": "c2", - } - ], - "http": [{"uri": "http://ip-api.com/line/?fields=hosting", "usage": "other"}], - "paths": [{"path": "newfile.exe", "usage": "storage"}], - } + if HAVE_MACO: + assert convert_to_MACO(conf).model_dump(exclude_defaults=True, exclude_none=True) == { + "family": "AgentTesla", + "other": { + "Protocol": "SMTP", + "C2": "mail.guestequipment.com.au", + "Username": "sendlog@guestequipment.com.au", + "Password": "Clone89!", + "EmailTo": "info@marethon.com", + "Persistence_Filename": "newfile.exe", + "ExternalIPCheckServices": ["http://ip-api.com/line/?fields=hosting"], + }, + "smtp": [ + { + "username": "sendlog@guestequipment.com.au", + "password": "Clone89!", + "hostname": "mail.guestequipment.com.au", + "mail_to": ["info@marethon.com"], + "usage": "c2", + } + ], + "http": [{"uri": "http://ip-api.com/line/?fields=hosting", "usage": "other"}], + "paths": [{"path": "newfile.exe", "usage": "storage"}], + } diff --git a/tests_parsers/test_asyncrat.py b/tests_parsers/test_asyncrat.py index 376e711751b..8394d0af6d5 100644 --- a/tests_parsers/test_asyncrat.py +++ b/tests_parsers/test_asyncrat.py @@ -1,5 +1,9 @@ from modules.processing.parsers.CAPE.AsyncRAT import extract_config -from modules.processing.parsers.MACO.AsyncRAT import convert_to_MACO +from contextlib import suppress +HAVE_MACO = False +with suppress(ImportError): + from modules.processing.parsers.MACO.AsyncRAT import convert_to_MACO + HAVE_MACO = True def test_asyncrat(): @@ -16,21 +20,22 @@ def test_asyncrat(): "Pastebin": "null", } - assert convert_to_MACO(conf).model_dump(exclude_defaults=True, exclude_none=True) == { - "family": "AsyncRAT", - "version": "0.5.7B", - "capability_disabled": ["persistence"], - "mutex": ["AsyncMutex_6SI8OkPnk"], - "other": { - "C2s": ["todfg.duckdns.org"], - "Ports": "6745", - "Version": "0.5.7B", - "Folder": "%AppData%", - "Filename": "updateee.exe", - "Install": "false", - "Mutex": "AsyncMutex_6SI8OkPnk", - "Pastebin": "null", - }, - "http": [{"hostname": "todfg.duckdns.org", "port": 6, "usage": "c2"}], - "paths": [{"path": "%AppData%/updateee.exe", "usage": "install"}], - } + if HAVE_MACO: + assert convert_to_MACO(conf).model_dump(exclude_defaults=True, exclude_none=True) == { + "family": "AsyncRAT", + "version": "0.5.7B", + "capability_disabled": ["persistence"], + "mutex": ["AsyncMutex_6SI8OkPnk"], + "other": { + "C2s": ["todfg.duckdns.org"], + "Ports": "6745", + "Version": "0.5.7B", + "Folder": "%AppData%", + "Filename": "updateee.exe", + "Install": "false", + "Mutex": "AsyncMutex_6SI8OkPnk", + "Pastebin": "null", + }, + "http": [{"hostname": "todfg.duckdns.org", "port": 6, "usage": "c2"}], + "paths": [{"path": "%AppData%/updateee.exe", "usage": "install"}], + } diff --git a/tests_parsers/test_aurorastealer.py b/tests_parsers/test_aurorastealer.py index 53af23b3f8c..ddb2b157cb9 100644 --- a/tests_parsers/test_aurorastealer.py +++ b/tests_parsers/test_aurorastealer.py @@ -1,5 +1,9 @@ from modules.processing.parsers.CAPE.AuroraStealer import extract_config -from modules.processing.parsers.MACO.AuroraStealer import convert_to_MACO +from contextlib import suppress +HAVE_MACO = False +with suppress(ImportError): + from modules.processing.parsers.MACO.AuroraStealer import convert_to_MACO + HAVE_MACO = True def test_aurorastealer(): @@ -15,16 +19,17 @@ def test_aurorastealer(): "Date": "2023-04-06 19", } - assert convert_to_MACO(conf).model_dump(exclude_defaults=True, exclude_none=True) == { - "family": "AuroraStealer", - "other": { - "BuildID": "x64pump", - "MD5Hash": "f29f33b296b35ec5e7fc3ee784ef68ee", - "C2": "77.91.85.73", - "Architecture": "X64", - "BuildGroup": "x64pump", - "BuildAccept": "0", - "Date": "2023-04-06 19", - }, - "http": [{"hostname": "77.91.85.73", "usage": "c2"}], - } + if HAVE_MACO: + assert convert_to_MACO(conf).model_dump(exclude_defaults=True, exclude_none=True) == { + "family": "AuroraStealer", + "other": { + "BuildID": "x64pump", + "MD5Hash": "f29f33b296b35ec5e7fc3ee784ef68ee", + "C2": "77.91.85.73", + "Architecture": "X64", + "BuildGroup": "x64pump", + "BuildAccept": "0", + "Date": "2023-04-06 19", + }, + "http": [{"hostname": "77.91.85.73", "usage": "c2"}], + } diff --git a/tests_parsers/test_blackdropper.py b/tests_parsers/test_blackdropper.py index 7e4dc59d067..d773329c4dc 100644 --- a/tests_parsers/test_blackdropper.py +++ b/tests_parsers/test_blackdropper.py @@ -3,7 +3,12 @@ # See the file 'docs/LICENSE' for copying permission. from modules.processing.parsers.CAPE.BlackDropper import extract_config -from modules.processing.parsers.MACO.BlackDropper import convert_to_MACO +from contextlib import suppress +HAVE_MACO = False +with suppress(ImportError): + from modules.processing.parsers.MACO.BlackDropper import convert_to_MACO + HAVE_MACO = True + def test_blackdropper(): @@ -15,14 +20,15 @@ def test_blackdropper(): "campaign": "oFwQ0aQ3v", } - assert convert_to_MACO(conf).model_dump(exclude_defaults=True, exclude_none=True) == { - "family": "BlackDropper", - "campaign_id": ["oFwQ0aQ3v"], - "other": { - "urls": ["http://72.5.42.222:8568/api/dll/", "http://72.5.42.222:8568/api/fileZip"], - "directories": ["\\Music\\dkcydqtwjv"], - "campaign": "oFwQ0aQ3v", - }, - "http": [{"uri": "http://72.5.42.222:8568/api/dll/"}, {"uri": "http://72.5.42.222:8568/api/fileZip"}], - "paths": [{"path": "\\Music\\dkcydqtwjv"}], - } + if HAVE_MACO: + assert convert_to_MACO(conf).model_dump(exclude_defaults=True, exclude_none=True) == { + "family": "BlackDropper", + "campaign_id": ["oFwQ0aQ3v"], + "other": { + "urls": ["http://72.5.42.222:8568/api/dll/", "http://72.5.42.222:8568/api/fileZip"], + "directories": ["\\Music\\dkcydqtwjv"], + "campaign": "oFwQ0aQ3v", + }, + "http": [{"uri": "http://72.5.42.222:8568/api/dll/"}, {"uri": "http://72.5.42.222:8568/api/fileZip"}], + "paths": [{"path": "\\Music\\dkcydqtwjv"}], + } diff --git a/tests_parsers/test_bumblebee.py b/tests_parsers/test_bumblebee.py index fd06f12ee10..3ac5f6b57c7 100644 --- a/tests_parsers/test_bumblebee.py +++ b/tests_parsers/test_bumblebee.py @@ -3,18 +3,23 @@ # See the file 'docs/LICENSE' for copying permission. from modules.processing.parsers.CAPE.BumbleBee import extract_config -from modules.processing.parsers.MACO.BumbleBee import convert_to_MACO +from contextlib import suppress +HAVE_MACO = False +with suppress(ImportError): + from modules.processing.parsers.MACO.BumbleBee import convert_to_MACO + HAVE_MACO = True def test_bumblebee(): with open("tests/data/malware/f8a6eddcec59934c42ea254cdd942fb62917b5898f71f0feeae6826ba4f3470d", "rb") as data: conf = extract_config(data.read()) assert conf == {"Botnet ID": "YTBSBbNTWU", "Campaign ID": "1904r", "Data": "XNgHUGLrCD", "C2s": ["444"]} - assert convert_to_MACO(conf).model_dump(exclude_defaults=True, exclude_none=True) == { - "family": "BumbleBee", - "campaign_id": ["1904r"], - "identifier": ["YTBSBbNTWU"], - "other": {"Botnet ID": "YTBSBbNTWU", "Campaign ID": "1904r", "Data": "XNgHUGLrCD", "C2s": ["444"]}, - "binaries": [{"data": "XNgHUGLrCD"}], - "http": [{"hostname": "444", "usage": "c2"}], - } + if HAVE_MACO: + assert convert_to_MACO(conf).model_dump(exclude_defaults=True, exclude_none=True) == { + "family": "BumbleBee", + "campaign_id": ["1904r"], + "identifier": ["YTBSBbNTWU"], + "other": {"Botnet ID": "YTBSBbNTWU", "Campaign ID": "1904r", "Data": "XNgHUGLrCD", "C2s": ["444"]}, + "binaries": [{"data": "XNgHUGLrCD"}], + "http": [{"hostname": "444", "usage": "c2"}], + } diff --git a/tests_parsers/test_carbanak.py b/tests_parsers/test_carbanak.py index 8d5169fea96..cb93c32bd58 100644 --- a/tests_parsers/test_carbanak.py +++ b/tests_parsers/test_carbanak.py @@ -1,13 +1,18 @@ from modules.processing.parsers.CAPE.Carbanak import extract_config -from modules.processing.parsers.MACO.Carbanak import convert_to_MACO +from contextlib import suppress +HAVE_MACO = False +with suppress(ImportError): + from modules.processing.parsers.MACO.Carbanak import convert_to_MACO + HAVE_MACO = True def test_carbanak(): with open("tests/data/malware/c9c1b06cb9c9bd6fc4451f5e2847a1f9524bb2870d7bb6f0ee09b9dd4e3e4c84", "rb") as data: conf = extract_config(data.read()) assert conf["C2"] == ["5.161.223.210:443", "207.174.30.226:443"] - assert convert_to_MACO(conf).model_dump(exclude_defaults=True, exclude_none=True) == { - "family": "Carbanak", - "other": {"C2": ["5.161.223.210:443", "207.174.30.226:443"]}, - "http": [{"hostname": "5.161.223.210:443", "usage": "c2"}, {"hostname": "207.174.30.226:443", "usage": "c2"}], - } + if HAVE_MACO: + assert convert_to_MACO(conf).model_dump(exclude_defaults=True, exclude_none=True) == { + "family": "Carbanak", + "other": {"C2": ["5.161.223.210:443", "207.174.30.226:443"]}, + "http": [{"hostname": "5.161.223.210:443", "usage": "c2"}, {"hostname": "207.174.30.226:443", "usage": "c2"}], + } diff --git a/tests_parsers/test_cobaltstrikebeacon.py b/tests_parsers/test_cobaltstrikebeacon.py index 47c26163b54..1c6451afec6 100644 --- a/tests_parsers/test_cobaltstrikebeacon.py +++ b/tests_parsers/test_cobaltstrikebeacon.py @@ -3,7 +3,12 @@ # See the file 'docs/LICENSE' for copying permission. from modules.processing.parsers.CAPE.CobaltStrikeBeacon import extract_config -from modules.processing.parsers.MACO.CobaltStrikeBeacon import convert_to_MACO +from contextlib import suppress +HAVE_MACO = False +with suppress(ImportError): + from modules.processing.parsers.MACO.CobaltStrikeBeacon import convert_to_MACO + HAVE_MACO = True + def test_csb(): @@ -56,62 +61,63 @@ def test_csb(): "bUsesCookies": "True", "HostHeader": "", } - assert convert_to_MACO(conf).model_dump(exclude_defaults=True, exclude_none=True) == { - "family": "CobaltStrikeBeacon", - "capability_enabled": ["ProcInject_StartRWX", "ProcInject_UseRWX", "UsesCookies"], - "capability_disabled": ["StageCleanup", "CFGCaution"], - "sleep_delay": 60000, - "sleep_delay_jitter": 0, - "other": { - "BeaconType": ["HTTP"], - "Port": 4848, - "SleepTime": 60000, - "MaxGetSize": 1048576, - "Jitter": 0, - "MaxDNS": "Not Found", - "PublicKey": "30819f300d06092a864886f70d010101050003818d0030818902818100bebe41805d3c15a738caf3e308a992d4d507ce827996a8c9d783c766963e7e73083111729ae0abc1b49af0bcf803efdcaf83ac694fb53d043a88e9333f169e026a3c4e63cc6d4cd1aa5e199cb95eec500f948ac472c0ab2eda385d35fb8592d74b1154a1c671afb310eccb0b139ee1100907bfcdd8dfbf3385803a11bc252995020301000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "C2Server": "192.144.206.100,/load", - "UserAgent": "Not Found", - "HttpPostUri": "/submit.php", - "Malleable_C2_Instructions": [], - "HttpGet_Metadata": "Not Found", - "HttpPost_Metadata": "Not Found", - "SpawnTo": "d7a9ca15a07f82bfd3b63020da38aa16", - "PipeName": "Not Found", - "DNS_Idle": "Not Found", - "DNS_Sleep": "Not Found", - "SSH_Host": "Not Found", - "SSH_Port": "Not Found", - "SSH_Username": "Not Found", - "SSH_Password_Plaintext": "Not Found", - "SSH_Password_Pubkey": "Not Found", - "HttpGet_Verb": "GET", - "HttpPost_Verb": "POST", - "HttpPostChunk": 0, - "Spawnto_x86": "%windir%\\syswow64\\rundll32.exe", - "Spawnto_x64": "%windir%\\sysnative\\rundll32.exe", - "CryptoScheme": 0, - "Proxy_Config": "Not Found", - "Proxy_User": "Not Found", - "Proxy_Password": "Not Found", - "Proxy_Behavior": "Use IE settings", - "Watermark": 391144938, - "bStageCleanup": "False", - "bCFGCaution": "False", - "KillDate": 0, - "bProcInject_StartRWX": "True", - "bProcInject_UseRWX": "True", - "bProcInject_MinAllocSize": 0, - "ProcInject_PrependAppend_x86": "Empty", - "ProcInject_PrependAppend_x64": "Empty", - "ProcInject_Execute": ["CreateThread", "SetThreadContext", "CreateRemoteThread", "RtlCreateUserThread"], - "ProcInject_AllocationMethod": "VirtualAllocEx", - "bUsesCookies": "True", - "HostHeader": "", - }, - "http": [ - {"hostname": "192.144.206.100", "port": 4848, "path": "/load", "method": "GET", "usage": "c2"}, - {"hostname": "192.144.206.100", "port": 4848, "path": "/submit.php", "method": "POST", "usage": "c2"}, - ], - "paths": [{"path": "%windir%\\syswow64\\rundll32.exe"}, {"path": "%windir%\\sysnative\\rundll32.exe"}], - } + if HAVE_MACO: + assert convert_to_MACO(conf).model_dump(exclude_defaults=True, exclude_none=True) == { + "family": "CobaltStrikeBeacon", + "capability_enabled": ["ProcInject_StartRWX", "ProcInject_UseRWX", "UsesCookies"], + "capability_disabled": ["StageCleanup", "CFGCaution"], + "sleep_delay": 60000, + "sleep_delay_jitter": 0, + "other": { + "BeaconType": ["HTTP"], + "Port": 4848, + "SleepTime": 60000, + "MaxGetSize": 1048576, + "Jitter": 0, + "MaxDNS": "Not Found", + "PublicKey": "30819f300d06092a864886f70d010101050003818d0030818902818100bebe41805d3c15a738caf3e308a992d4d507ce827996a8c9d783c766963e7e73083111729ae0abc1b49af0bcf803efdcaf83ac694fb53d043a88e9333f169e026a3c4e63cc6d4cd1aa5e199cb95eec500f948ac472c0ab2eda385d35fb8592d74b1154a1c671afb310eccb0b139ee1100907bfcdd8dfbf3385803a11bc252995020301000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "C2Server": "192.144.206.100,/load", + "UserAgent": "Not Found", + "HttpPostUri": "/submit.php", + "Malleable_C2_Instructions": [], + "HttpGet_Metadata": "Not Found", + "HttpPost_Metadata": "Not Found", + "SpawnTo": "d7a9ca15a07f82bfd3b63020da38aa16", + "PipeName": "Not Found", + "DNS_Idle": "Not Found", + "DNS_Sleep": "Not Found", + "SSH_Host": "Not Found", + "SSH_Port": "Not Found", + "SSH_Username": "Not Found", + "SSH_Password_Plaintext": "Not Found", + "SSH_Password_Pubkey": "Not Found", + "HttpGet_Verb": "GET", + "HttpPost_Verb": "POST", + "HttpPostChunk": 0, + "Spawnto_x86": "%windir%\\syswow64\\rundll32.exe", + "Spawnto_x64": "%windir%\\sysnative\\rundll32.exe", + "CryptoScheme": 0, + "Proxy_Config": "Not Found", + "Proxy_User": "Not Found", + "Proxy_Password": "Not Found", + "Proxy_Behavior": "Use IE settings", + "Watermark": 391144938, + "bStageCleanup": "False", + "bCFGCaution": "False", + "KillDate": 0, + "bProcInject_StartRWX": "True", + "bProcInject_UseRWX": "True", + "bProcInject_MinAllocSize": 0, + "ProcInject_PrependAppend_x86": "Empty", + "ProcInject_PrependAppend_x64": "Empty", + "ProcInject_Execute": ["CreateThread", "SetThreadContext", "CreateRemoteThread", "RtlCreateUserThread"], + "ProcInject_AllocationMethod": "VirtualAllocEx", + "bUsesCookies": "True", + "HostHeader": "", + }, + "http": [ + {"hostname": "192.144.206.100", "port": 4848, "path": "/load", "method": "GET", "usage": "c2"}, + {"hostname": "192.144.206.100", "port": 4848, "path": "/submit.php", "method": "POST", "usage": "c2"}, + ], + "paths": [{"path": "%windir%\\syswow64\\rundll32.exe"}, {"path": "%windir%\\sysnative\\rundll32.exe"}], + } diff --git a/tests_parsers/test_darkgate.py b/tests_parsers/test_darkgate.py index 9a32a515a5a..7a46843a84e 100644 --- a/tests_parsers/test_darkgate.py +++ b/tests_parsers/test_darkgate.py @@ -1,13 +1,18 @@ from modules.processing.parsers.CAPE.DarkGate import extract_config -from modules.processing.parsers.MACO.DarkGate import convert_to_MACO +from contextlib import suppress +HAVE_MACO = False +with suppress(ImportError): + from modules.processing.parsers.MACO.DarkGate import convert_to_MACO + HAVE_MACO = True def test_darkgate(): with open("tests/data/malware/1c3ae64795b61034080be00601b947819fe071efd69d7fc791a99ec666c2043d", "rb") as data: conf = extract_config(data.read()) assert conf["C2"] == ["http://80.66.88.145"] - assert convert_to_MACO(conf).model_dump(exclude_defaults=True, exclude_none=True) == { - "family": "DarkGate", - "other": {"C2": ["http://80.66.88.145"]}, - "http": [{"uri": "http://80.66.88.145", "usage": "c2"}], - } + if HAVE_MACO: + assert convert_to_MACO(conf).model_dump(exclude_defaults=True, exclude_none=True) == { + "family": "DarkGate", + "other": {"C2": ["http://80.66.88.145"]}, + "http": [{"uri": "http://80.66.88.145", "usage": "c2"}], + } diff --git a/tests_parsers/test_icedid.py b/tests_parsers/test_icedid.py index 590591c2701..4a8c93fc529 100644 --- a/tests_parsers/test_icedid.py +++ b/tests_parsers/test_icedid.py @@ -1,14 +1,19 @@ from modules.processing.parsers.CAPE.IcedIDLoader import extract_config -from modules.processing.parsers.MACO.IcedIDLoader import convert_to_MACO +from contextlib import suppress +HAVE_MACO = False +with suppress(ImportError): + from modules.processing.parsers.MACO.IcedIDLoader import convert_to_MACO + HAVE_MACO = True def test_icedid(): with open("tests/data/malware/7aaf80eb1436b946b2bd710ab57d2dcbaad2b1553d45602f2f3af6f2cfca5212", "rb") as data: conf = extract_config(data.read()) assert conf == {"C2": "anscowerbrut.com", "Campaign": 2738000827} - assert convert_to_MACO(conf).model_dump(exclude_defaults=True, exclude_none=True) == { - "family": "IcedIDLoader", - "campaign_id": ["2738000827"], - "other": {"C2": "anscowerbrut.com", "Campaign": 2738000827}, - "http": [{"hostname": "anscowerbrut.com", "usage": "c2"}], - } + if HAVE_MACO: + assert convert_to_MACO(conf).model_dump(exclude_defaults=True, exclude_none=True) == { + "family": "IcedIDLoader", + "campaign_id": ["2738000827"], + "other": {"C2": "anscowerbrut.com", "Campaign": 2738000827}, + "http": [{"hostname": "anscowerbrut.com", "usage": "c2"}], + } diff --git a/tests_parsers/test_koiloader.py b/tests_parsers/test_koiloader.py index 8844a08acef..0e9a3a01020 100644 --- a/tests_parsers/test_koiloader.py +++ b/tests_parsers/test_koiloader.py @@ -3,18 +3,22 @@ # See the file 'docs/LICENSE' for copying permission. from modules.processing.parsers.CAPE.KoiLoader import extract_config -from modules.processing.parsers.MACO.KoiLoader import convert_to_MACO - +from contextlib import suppress +HAVE_MACO = False +with suppress(ImportError): + from modules.processing.parsers.MACO.KoiLoader import convert_to_MACO + HAVE_MACO = True def test_koiloader(): with open("tests/data/malware/b462e3235c7578450b2b56a8aff875a3d99d22f6970a01db3ba98f7ecb6b01a0", "rb") as data: conf = extract_config(data.read()) assert conf == {"C2": ["http://91.202.233.209/hypermetropia.php", "https://admiralpub.ca/wp-content/uploads/2017"]} - assert convert_to_MACO(conf).model_dump(exclude_defaults=True, exclude_none=True) == { - "family": "KoiLoader", - "other": {"C2": ["http://91.202.233.209/hypermetropia.php", "https://admiralpub.ca/wp-content/uploads/2017"]}, - "http": [ - {"uri": "http://91.202.233.209/hypermetropia.php", "usage": "c2"}, - {"uri": "https://admiralpub.ca/wp-content/uploads/2017", "usage": "c2"}, - ], - } + if HAVE_MACO: + assert convert_to_MACO(conf).model_dump(exclude_defaults=True, exclude_none=True) == { + "family": "KoiLoader", + "other": {"C2": ["http://91.202.233.209/hypermetropia.php", "https://admiralpub.ca/wp-content/uploads/2017"]}, + "http": [ + {"uri": "http://91.202.233.209/hypermetropia.php", "usage": "c2"}, + {"uri": "https://admiralpub.ca/wp-content/uploads/2017", "usage": "c2"}, + ], + } diff --git a/tests_parsers/test_latrodectus.py b/tests_parsers/test_latrodectus.py index d71d20a4977..31aab069bad 100644 --- a/tests_parsers/test_latrodectus.py +++ b/tests_parsers/test_latrodectus.py @@ -3,7 +3,11 @@ # See the file 'docs/LICENSE' for copying permission. from modules.processing.parsers.CAPE.Latrodectus import extract_config -from modules.processing.parsers.MACO.Latrodectus import convert_to_MACO +from contextlib import suppress +HAVE_MACO = False +with suppress(ImportError): + from modules.processing.parsers.MACO.Latrodectus import convert_to_MACO + HAVE_MACO = True def test_latrodectus(): @@ -99,101 +103,13 @@ def test_latrodectus(): "URLS|%d|%s\r\n", ], } - assert convert_to_MACO(conf).model_dump(exclude_defaults=True, exclude_none=True) == { - "family": "Latrodectus", - "version": "1.1", - "campaign_id": ["1053565364"], - "identifier": ["Novik"], - "decoded_strings": [ - "/c ipconfig /all", - "C:\\Windows\\System32\\cmd.exe", - "/c systeminfo", - "C:\\Windows\\System32\\cmd.exe", - "/c nltest /domain_trusts", - "C:\\Windows\\System32\\cmd.exe", - "/c nltest /domain_trusts /all_trusts", - "C:\\Windows\\System32\\cmd.exe", - "/c net view /all /domain", - "C:\\Windows\\System32\\cmd.exe", - "/c net view /all", - "C:\\Windows\\System32\\cmd.exe", - '/c net group "Domain Admins" /domain', - "C:\\Windows\\System32\\cmd.exe", - "/Node:localhost /Namespace:\\\\root\\SecurityCenter2 Path AntiVirusProduct Get * /Format:List", - "C:\\Windows\\System32\\wbem\\wmic.exe", - "/c net config workstation", - "C:\\Windows\\System32\\cmd.exe", - "/c wmic.exe /node:localhost /namespace:\\\\root\\SecurityCenter2 path AntiVirusProduct Get DisplayName | findstr /V /B /C:displayName || echo No Antivirus installed", - "C:\\Windows\\System32\\cmd.exe", - "/c whoami /groups", - "C:\\Windows\\System32\\cmd.exe", - ".dll", - ".exe", - '"%s"', - "rundll32.exe", - '"%s", %s %s', - "runnung", - ":wtfbbq", - "%s%s", - "%s\\%d.dll", - "%d.dat", - "%s\\%s", - 'init -zzzz="%s\\%s"', - "front", - "/files/", - "Novik", - ".exe", - "Content-Type: application/x-www-form-urlencoded", - "POST", - "GET", - "curl/7.88.1", - "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Tob 1.1)", - "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Tob 1.1)", - "CLEARURL", - "URLS", - "COMMAND", - "ERROR", - "12345", - "counter=%d&type=%d&guid=%s&os=%d&arch=%d&username=%s&group=%lu&ver=%d.%d&up=%d&direction=%s", - "counter=%d&type=%d&guid=%s&os=%d&arch=%d&username=%s&group=%lu&ver=%d.%d&up=%d&direction=%s", - "counter=%d&type=%d&guid=%s&os=%d&arch=%d&username=%s&group=%lu&ver=%d.%d&up=%d&direction=%s", - "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Tob 1.1)", - "%s%d.dll", - "%s%d.exe", - "LogonTrigger", - "%x%x", - "TimeTrigger", - "PT1H%02dM", - "&mac=", - "%04d-%02d-%02dT%02d:%02d:%02d", - "%02x", - ":%02x", - "PT0S", - "&computername=%s", - "&domain=%s", - "\\*.dll", - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/", - "%04X%04X%04X%04X%08X%04X", - "%04X%04X%04X%04X%08X%04X", - "\\Registry\\Machine\\", - "AppData", - "Desktop", - "Startup", - "Personal", - "Local AppData", - "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders", - "C:\\WINDOWS\\SYSTEM32\\rundll32.exe %s,%s", - "C:\\WINDOWS\\SYSTEM32\\rundll32.exe %s", - "URLS", - "URLS|%d|%s\r\n", - ], - "other": { - "C2": ["https://arsimonopa.com/live/", "https://lemonimonakio.com/live/"], - "Group name": "Novik", - "Campaign ID": 1053565364, - "Version": "1.1", - "RC4 key": "12345", - "Strings": [ + if HAVE_MACO: + assert convert_to_MACO(conf).model_dump(exclude_defaults=True, exclude_none=True) == { + "family": "Latrodectus", + "version": "1.1", + "campaign_id": ["1053565364"], + "identifier": ["Novik"], + "decoded_strings": [ "/c ipconfig /all", "C:\\Windows\\System32\\cmd.exe", "/c systeminfo", @@ -276,10 +192,99 @@ def test_latrodectus(): "URLS", "URLS|%d|%s\r\n", ], - }, - "http": [ - {"uri": "https://arsimonopa.com/live/", "usage": "c2"}, - {"uri": "https://lemonimonakio.com/live/", "usage": "c2"}, - ], - "encryption": [{"algorithm": "RC4", "key": "12345"}], - } + "other": { + "C2": ["https://arsimonopa.com/live/", "https://lemonimonakio.com/live/"], + "Group name": "Novik", + "Campaign ID": 1053565364, + "Version": "1.1", + "RC4 key": "12345", + "Strings": [ + "/c ipconfig /all", + "C:\\Windows\\System32\\cmd.exe", + "/c systeminfo", + "C:\\Windows\\System32\\cmd.exe", + "/c nltest /domain_trusts", + "C:\\Windows\\System32\\cmd.exe", + "/c nltest /domain_trusts /all_trusts", + "C:\\Windows\\System32\\cmd.exe", + "/c net view /all /domain", + "C:\\Windows\\System32\\cmd.exe", + "/c net view /all", + "C:\\Windows\\System32\\cmd.exe", + '/c net group "Domain Admins" /domain', + "C:\\Windows\\System32\\cmd.exe", + "/Node:localhost /Namespace:\\\\root\\SecurityCenter2 Path AntiVirusProduct Get * /Format:List", + "C:\\Windows\\System32\\wbem\\wmic.exe", + "/c net config workstation", + "C:\\Windows\\System32\\cmd.exe", + "/c wmic.exe /node:localhost /namespace:\\\\root\\SecurityCenter2 path AntiVirusProduct Get DisplayName | findstr /V /B /C:displayName || echo No Antivirus installed", + "C:\\Windows\\System32\\cmd.exe", + "/c whoami /groups", + "C:\\Windows\\System32\\cmd.exe", + ".dll", + ".exe", + '"%s"', + "rundll32.exe", + '"%s", %s %s', + "runnung", + ":wtfbbq", + "%s%s", + "%s\\%d.dll", + "%d.dat", + "%s\\%s", + 'init -zzzz="%s\\%s"', + "front", + "/files/", + "Novik", + ".exe", + "Content-Type: application/x-www-form-urlencoded", + "POST", + "GET", + "curl/7.88.1", + "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Tob 1.1)", + "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Tob 1.1)", + "CLEARURL", + "URLS", + "COMMAND", + "ERROR", + "12345", + "counter=%d&type=%d&guid=%s&os=%d&arch=%d&username=%s&group=%lu&ver=%d.%d&up=%d&direction=%s", + "counter=%d&type=%d&guid=%s&os=%d&arch=%d&username=%s&group=%lu&ver=%d.%d&up=%d&direction=%s", + "counter=%d&type=%d&guid=%s&os=%d&arch=%d&username=%s&group=%lu&ver=%d.%d&up=%d&direction=%s", + "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Tob 1.1)", + "%s%d.dll", + "%s%d.exe", + "LogonTrigger", + "%x%x", + "TimeTrigger", + "PT1H%02dM", + "&mac=", + "%04d-%02d-%02dT%02d:%02d:%02d", + "%02x", + ":%02x", + "PT0S", + "&computername=%s", + "&domain=%s", + "\\*.dll", + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/", + "%04X%04X%04X%04X%08X%04X", + "%04X%04X%04X%04X%08X%04X", + "\\Registry\\Machine\\", + "AppData", + "Desktop", + "Startup", + "Personal", + "Local AppData", + "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders", + "C:\\WINDOWS\\SYSTEM32\\rundll32.exe %s,%s", + "C:\\WINDOWS\\SYSTEM32\\rundll32.exe %s", + "URLS", + "URLS|%d|%s\r\n", + ], + }, + "http": [ + {"uri": "https://arsimonopa.com/live/", "usage": "c2"}, + {"uri": "https://lemonimonakio.com/live/", "usage": "c2"}, + ], + "encryption": [{"algorithm": "RC4", "key": "12345"}], + } diff --git a/tests_parsers/test_lumma.py b/tests_parsers/test_lumma.py index 6f13eb15f3e..c681636e01b 100644 --- a/tests_parsers/test_lumma.py +++ b/tests_parsers/test_lumma.py @@ -3,7 +3,11 @@ # See the file 'docs/LICENSE' for copying permission. from modules.processing.parsers.CAPE.Lumma import extract_config -from modules.processing.parsers.MACO.Lumma import convert_to_MACO +from contextlib import suppress +HAVE_MACO = False +with suppress(ImportError): + from modules.processing.parsers.MACO.Lumma import convert_to_MACO + HAVE_MACO = True def test_lumma(): @@ -22,30 +26,31 @@ def test_lumma(): "agentyanlark.site", ] } - assert convert_to_MACO(conf).model_dump(exclude_defaults=True, exclude_none=True) == { - "family": "Lumma", - "other": { - "C2": [ - "delaylacedmn.site", - "writekdmsnu.site", - "agentyanlark.site", - "bellykmrebk.site", - "underlinemdsj.site", - "commandejorsk.site", - "possiwreeste.site", - "famikyjdiag.site", - "agentyanlark.site", - ] - }, - "http": [ - {"hostname": "delaylacedmn.site", "usage": "c2"}, - {"hostname": "writekdmsnu.site", "usage": "c2"}, - {"hostname": "agentyanlark.site", "usage": "c2"}, - {"hostname": "bellykmrebk.site", "usage": "c2"}, - {"hostname": "underlinemdsj.site", "usage": "c2"}, - {"hostname": "commandejorsk.site", "usage": "c2"}, - {"hostname": "possiwreeste.site", "usage": "c2"}, - {"hostname": "famikyjdiag.site", "usage": "c2"}, - {"hostname": "agentyanlark.site", "usage": "c2"}, - ], - } + if HAVE_MACO: + assert convert_to_MACO(conf).model_dump(exclude_defaults=True, exclude_none=True) == { + "family": "Lumma", + "other": { + "C2": [ + "delaylacedmn.site", + "writekdmsnu.site", + "agentyanlark.site", + "bellykmrebk.site", + "underlinemdsj.site", + "commandejorsk.site", + "possiwreeste.site", + "famikyjdiag.site", + "agentyanlark.site", + ] + }, + "http": [ + {"hostname": "delaylacedmn.site", "usage": "c2"}, + {"hostname": "writekdmsnu.site", "usage": "c2"}, + {"hostname": "agentyanlark.site", "usage": "c2"}, + {"hostname": "bellykmrebk.site", "usage": "c2"}, + {"hostname": "underlinemdsj.site", "usage": "c2"}, + {"hostname": "commandejorsk.site", "usage": "c2"}, + {"hostname": "possiwreeste.site", "usage": "c2"}, + {"hostname": "famikyjdiag.site", "usage": "c2"}, + {"hostname": "agentyanlark.site", "usage": "c2"}, + ], + } diff --git a/tests_parsers/test_nanocore.py b/tests_parsers/test_nanocore.py index 445f2127e82..c0aeba7a3a4 100644 --- a/tests_parsers/test_nanocore.py +++ b/tests_parsers/test_nanocore.py @@ -3,7 +3,11 @@ # See the file 'docs/LICENSE' for copying permission. from modules.processing.parsers.CAPE.NanoCore import extract_config -from modules.processing.parsers.MACO.NanoCore import convert_to_MACO +from contextlib import suppress +HAVE_MACO = False +with suppress(ImportError): + from modules.processing.parsers.MACO.NanoCore import convert_to_MACO + HAVE_MACO = True def test_nanocore(): @@ -42,59 +46,60 @@ def test_nanocore(): "BackupDnsServer": "8.8.4.4", "cncs": ["6coinc.zapto.org:6696", "127.0.0.1:6696"], } - assert convert_to_MACO(conf).model_dump(exclude_defaults=True, exclude_none=True) == { - "family": "NanoCore", - "version": "1.2.2.0", - "capability_enabled": [ - "RunOnStartup", - "BypassUserAccountControl", - "ClearZoneIdentifier", - "PreventSystemSleep", - "UseCustomDnsServer", - ], - "capability_disabled": [ - "RequestElevation", - "ClearAccessControl", - "SetCriticalProcess", - "ActivateAwayMode", - "EnableDebugMode", - ], - "mutex": ["dc5ce709-95b6-4a26-9175-16a1a8446828"], - "other": { - "BuildTime": "2023-11-22 00:25:26.569697", - "Version": "1.2.2.0", - "Mutex": "dc5ce709-95b6-4a26-9175-16a1a8446828", - "DefaultGroup": "6coinc", - "PrimaryConnectionHost": "6coinc.zapto.org", - "BackupConnectionHost": "127.0.0.1", - "ConnectionPort": "6696", - "RunOnStartup": "True", - "RequestElevation": "False", - "BypassUserAccountControl": "True", - "ClearZoneIdentifier": "True", - "ClearAccessControl": "False", - "SetCriticalProcess": "False", - "PreventSystemSleep": "True", - "ActivateAwayMode": "False", - "EnableDebugMode": "False", - "RunDelay": "0", - "ConnectDelay": "4000", - "RestartDelay": "5000", - "TimeoutInterval": "5000", - "KeepAliveTimeout": "30000", - "MutexTimeout": "5000", - "LanTimeout": "2500", - "WanTimeout": "8000", - "BufferSize": "65535", - "MaxPacketSize": "10485760", - "GCThreshold": "10485760", - "UseCustomDnsServer": "True", - "PrimaryDnsServer": "8.8.8.8", - "BackupDnsServer": "8.8.4.4", - "cncs": ["6coinc.zapto.org:6696", "127.0.0.1:6696"], - }, - "http": [ - {"hostname": "6coinc.zapto.org", "port": 6696, "usage": "c2"}, - {"hostname": "127.0.0.1", "port": 6696, "usage": "c2"}, - ], - } + if HAVE_MACO: + assert convert_to_MACO(conf).model_dump(exclude_defaults=True, exclude_none=True) == { + "family": "NanoCore", + "version": "1.2.2.0", + "capability_enabled": [ + "RunOnStartup", + "BypassUserAccountControl", + "ClearZoneIdentifier", + "PreventSystemSleep", + "UseCustomDnsServer", + ], + "capability_disabled": [ + "RequestElevation", + "ClearAccessControl", + "SetCriticalProcess", + "ActivateAwayMode", + "EnableDebugMode", + ], + "mutex": ["dc5ce709-95b6-4a26-9175-16a1a8446828"], + "other": { + "BuildTime": "2023-11-22 00:25:26.569697", + "Version": "1.2.2.0", + "Mutex": "dc5ce709-95b6-4a26-9175-16a1a8446828", + "DefaultGroup": "6coinc", + "PrimaryConnectionHost": "6coinc.zapto.org", + "BackupConnectionHost": "127.0.0.1", + "ConnectionPort": "6696", + "RunOnStartup": "True", + "RequestElevation": "False", + "BypassUserAccountControl": "True", + "ClearZoneIdentifier": "True", + "ClearAccessControl": "False", + "SetCriticalProcess": "False", + "PreventSystemSleep": "True", + "ActivateAwayMode": "False", + "EnableDebugMode": "False", + "RunDelay": "0", + "ConnectDelay": "4000", + "RestartDelay": "5000", + "TimeoutInterval": "5000", + "KeepAliveTimeout": "30000", + "MutexTimeout": "5000", + "LanTimeout": "2500", + "WanTimeout": "8000", + "BufferSize": "65535", + "MaxPacketSize": "10485760", + "GCThreshold": "10485760", + "UseCustomDnsServer": "True", + "PrimaryDnsServer": "8.8.8.8", + "BackupDnsServer": "8.8.4.4", + "cncs": ["6coinc.zapto.org:6696", "127.0.0.1:6696"], + }, + "http": [ + {"hostname": "6coinc.zapto.org", "port": 6696, "usage": "c2"}, + {"hostname": "127.0.0.1", "port": 6696, "usage": "c2"}, + ], + } diff --git a/tests_parsers/test_njrat.py b/tests_parsers/test_njrat.py index 5fb816a30a1..17729a6d9c1 100644 --- a/tests_parsers/test_njrat.py +++ b/tests_parsers/test_njrat.py @@ -3,7 +3,11 @@ # See the file 'docs/LICENSE' for copying permission. from modules.processing.parsers.CAPE.Njrat import extract_config -from modules.processing.parsers.MACO.Njrat import convert_to_MACO +from contextlib import suppress +HAVE_MACO = False +with suppress(ImportError): + from modules.processing.parsers.MACO.Njrat import convert_to_MACO + HAVE_MACO = True def test_njrat(): @@ -14,16 +18,17 @@ def test_njrat(): "campaign id": "HacKed", "version": "Njrat 0.7 Golden By Hassan Amiri", } - assert convert_to_MACO(conf).model_dump(exclude_defaults=True, exclude_none=True) == { - "family": "Njrat", - "version": "Njrat 0.7 Golden By Hassan Amiri", - "other": { - "cncs": ["peter-bikini.gl.at.ply.gg:64215"], - "campaign id": "HacKed", + if HAVE_MACO: + assert convert_to_MACO(conf).model_dump(exclude_defaults=True, exclude_none=True) == { + "family": "Njrat", "version": "Njrat 0.7 Golden By Hassan Amiri", - }, - "http": [{"hostname": "peter-bikini.gl.at.ply.gg", "port": 64215, "usage": "c2"}], - } + "other": { + "cncs": ["peter-bikini.gl.at.ply.gg:64215"], + "campaign id": "HacKed", + "version": "Njrat 0.7 Golden By Hassan Amiri", + }, + "http": [{"hostname": "peter-bikini.gl.at.ply.gg", "port": 64215, "usage": "c2"}], + } """ diff --git a/tests_parsers/test_oyster.py b/tests_parsers/test_oyster.py index ed758e42362..d831764f686 100644 --- a/tests_parsers/test_oyster.py +++ b/tests_parsers/test_oyster.py @@ -3,7 +3,11 @@ # See the file 'docs/LICENSE' for copying permission. from modules.processing.parsers.CAPE.Oyster import extract_config -from modules.processing.parsers.MACO.Oyster import convert_to_MACO +from contextlib import suppress +HAVE_MACO = False +with suppress(ImportError): + from modules.processing.parsers.MACO.Oyster import convert_to_MACO + HAVE_MACO = True def test_oyster(): @@ -14,14 +18,15 @@ def test_oyster(): "Dll Version": "v1.0 #ads 2", "Strings": ["api/connect", "Content-Type: application/json", "api/session"], } - assert convert_to_MACO(conf).model_dump(exclude_defaults=True, exclude_none=True) == { - "family": "Oyster", - "version": "v1.0 #ads 2", - "decoded_strings": ["api/connect", "Content-Type: application/json", "api/session"], - "other": { - "C2": ["https://connectivity-check.linkpc.net/"], - "Dll Version": "v1.0 #ads 2", - "Strings": ["api/connect", "Content-Type: application/json", "api/session"], - }, - "http": [{"uri": "https://connectivity-check.linkpc.net/", "usage": "c2"}], - } + if HAVE_MACO: + assert convert_to_MACO(conf).model_dump(exclude_defaults=True, exclude_none=True) == { + "family": "Oyster", + "version": "v1.0 #ads 2", + "decoded_strings": ["api/connect", "Content-Type: application/json", "api/session"], + "other": { + "C2": ["https://connectivity-check.linkpc.net/"], + "Dll Version": "v1.0 #ads 2", + "Strings": ["api/connect", "Content-Type: application/json", "api/session"], + }, + "http": [{"uri": "https://connectivity-check.linkpc.net/", "usage": "c2"}], + } diff --git a/tests_parsers/test_pikabot.py b/tests_parsers/test_pikabot.py index 18bc7018f06..318b9f17a06 100644 --- a/tests_parsers/test_pikabot.py +++ b/tests_parsers/test_pikabot.py @@ -3,7 +3,11 @@ # See the file 'docs/LICENSE' for copying permission. from modules.processing.parsers.CAPE.PikaBot import extract_config -from modules.processing.parsers.MACO.PikaBot import convert_to_MACO +from contextlib import suppress +HAVE_MACO = False +with suppress(ImportError): + from modules.processing.parsers.MACO.PikaBot import convert_to_MACO + HAVE_MACO = True def test_pikabot(): @@ -28,85 +32,86 @@ def test_pikabot(): "Campaign Name": "GG24_T@T@f0adda360d2b4ccda11468e026526576", "Registry Key": "MWnkl", } - assert convert_to_MACO(conf).model_dump(exclude_defaults=True, exclude_none=True) == { - "family": "PikaBot", - "version": "1.8.32-beta", - "campaign_id": ["GG24_T@T@f0adda360d2b4ccda11468e026526576"], - "other": { - "C2s": [ - "154.53.55.165:13783", - "158.247.240.58:5632", - "70.34.223.164:5000", - "70.34.199.64:9785", - "45.77.63.237:5632", - "198.38.94.213:2224", - "94.72.104.80:5000", - "84.46.240.42:2083", - "154.12.236.248:13786", - "94.72.104.77:13724", - "209.126.86.48:1194", - ], - "Version": "1.8.32-beta", - "User Agent": "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; Trident/7.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E; A7F; BRI/2; Tablet PC 2.0; wbx 1.0.0; Microsoft Outlook 14.0.7233; ms-office;", - "Campaign Name": "GG24_T@T@f0adda360d2b4ccda11468e026526576", - "Registry Key": "MWnkl", - }, - "http": [ - { - "hostname": "154.53.55.165", - "port": 13783, - "user_agent": "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; Trident/7.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E; A7F; BRI/2; Tablet PC 2.0; wbx 1.0.0; Microsoft Outlook 14.0.7233; ms-office;", - }, - { - "hostname": "158.247.240.58", - "port": 5632, - "user_agent": "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; Trident/7.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E; A7F; BRI/2; Tablet PC 2.0; wbx 1.0.0; Microsoft Outlook 14.0.7233; ms-office;", - }, - { - "hostname": "70.34.223.164", - "port": 5000, - "user_agent": "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; Trident/7.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E; A7F; BRI/2; Tablet PC 2.0; wbx 1.0.0; Microsoft Outlook 14.0.7233; ms-office;", - }, - { - "hostname": "70.34.199.64", - "port": 9785, - "user_agent": "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; Trident/7.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E; A7F; BRI/2; Tablet PC 2.0; wbx 1.0.0; Microsoft Outlook 14.0.7233; ms-office;", - }, - { - "hostname": "45.77.63.237", - "port": 5632, - "user_agent": "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; Trident/7.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E; A7F; BRI/2; Tablet PC 2.0; wbx 1.0.0; Microsoft Outlook 14.0.7233; ms-office;", - }, - { - "hostname": "198.38.94.213", - "port": 2224, - "user_agent": "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; Trident/7.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E; A7F; BRI/2; Tablet PC 2.0; wbx 1.0.0; Microsoft Outlook 14.0.7233; ms-office;", - }, - { - "hostname": "94.72.104.80", - "port": 5000, - "user_agent": "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; Trident/7.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E; A7F; BRI/2; Tablet PC 2.0; wbx 1.0.0; Microsoft Outlook 14.0.7233; ms-office;", + if HAVE_MACO: + assert convert_to_MACO(conf).model_dump(exclude_defaults=True, exclude_none=True) == { + "family": "PikaBot", + "version": "1.8.32-beta", + "campaign_id": ["GG24_T@T@f0adda360d2b4ccda11468e026526576"], + "other": { + "C2s": [ + "154.53.55.165:13783", + "158.247.240.58:5632", + "70.34.223.164:5000", + "70.34.199.64:9785", + "45.77.63.237:5632", + "198.38.94.213:2224", + "94.72.104.80:5000", + "84.46.240.42:2083", + "154.12.236.248:13786", + "94.72.104.77:13724", + "209.126.86.48:1194", + ], + "Version": "1.8.32-beta", + "User Agent": "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; Trident/7.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E; A7F; BRI/2; Tablet PC 2.0; wbx 1.0.0; Microsoft Outlook 14.0.7233; ms-office;", + "Campaign Name": "GG24_T@T@f0adda360d2b4ccda11468e026526576", + "Registry Key": "MWnkl", }, - { - "hostname": "84.46.240.42", - "port": 2083, - "user_agent": "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; Trident/7.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E; A7F; BRI/2; Tablet PC 2.0; wbx 1.0.0; Microsoft Outlook 14.0.7233; ms-office;", - }, - { - "hostname": "154.12.236.248", - "port": 13786, - "user_agent": "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; Trident/7.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E; A7F; BRI/2; Tablet PC 2.0; wbx 1.0.0; Microsoft Outlook 14.0.7233; ms-office;", - }, - { - "hostname": "94.72.104.77", - "port": 13724, - "user_agent": "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; Trident/7.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E; A7F; BRI/2; Tablet PC 2.0; wbx 1.0.0; Microsoft Outlook 14.0.7233; ms-office;", - }, - { - "hostname": "209.126.86.48", - "port": 1194, - "user_agent": "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; Trident/7.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E; A7F; BRI/2; Tablet PC 2.0; wbx 1.0.0; Microsoft Outlook 14.0.7233; ms-office;", - }, - ], - "registry": [{"key": "MWnkl"}], - } + "http": [ + { + "hostname": "154.53.55.165", + "port": 13783, + "user_agent": "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; Trident/7.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E; A7F; BRI/2; Tablet PC 2.0; wbx 1.0.0; Microsoft Outlook 14.0.7233; ms-office;", + }, + { + "hostname": "158.247.240.58", + "port": 5632, + "user_agent": "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; Trident/7.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E; A7F; BRI/2; Tablet PC 2.0; wbx 1.0.0; Microsoft Outlook 14.0.7233; ms-office;", + }, + { + "hostname": "70.34.223.164", + "port": 5000, + "user_agent": "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; Trident/7.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E; A7F; BRI/2; Tablet PC 2.0; wbx 1.0.0; Microsoft Outlook 14.0.7233; ms-office;", + }, + { + "hostname": "70.34.199.64", + "port": 9785, + "user_agent": "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; Trident/7.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E; A7F; BRI/2; Tablet PC 2.0; wbx 1.0.0; Microsoft Outlook 14.0.7233; ms-office;", + }, + { + "hostname": "45.77.63.237", + "port": 5632, + "user_agent": "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; Trident/7.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E; A7F; BRI/2; Tablet PC 2.0; wbx 1.0.0; Microsoft Outlook 14.0.7233; ms-office;", + }, + { + "hostname": "198.38.94.213", + "port": 2224, + "user_agent": "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; Trident/7.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E; A7F; BRI/2; Tablet PC 2.0; wbx 1.0.0; Microsoft Outlook 14.0.7233; ms-office;", + }, + { + "hostname": "94.72.104.80", + "port": 5000, + "user_agent": "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; Trident/7.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E; A7F; BRI/2; Tablet PC 2.0; wbx 1.0.0; Microsoft Outlook 14.0.7233; ms-office;", + }, + { + "hostname": "84.46.240.42", + "port": 2083, + "user_agent": "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; Trident/7.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E; A7F; BRI/2; Tablet PC 2.0; wbx 1.0.0; Microsoft Outlook 14.0.7233; ms-office;", + }, + { + "hostname": "154.12.236.248", + "port": 13786, + "user_agent": "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; Trident/7.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E; A7F; BRI/2; Tablet PC 2.0; wbx 1.0.0; Microsoft Outlook 14.0.7233; ms-office;", + }, + { + "hostname": "94.72.104.77", + "port": 13724, + "user_agent": "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; Trident/7.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E; A7F; BRI/2; Tablet PC 2.0; wbx 1.0.0; Microsoft Outlook 14.0.7233; ms-office;", + }, + { + "hostname": "209.126.86.48", + "port": 1194, + "user_agent": "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; Trident/7.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E; A7F; BRI/2; Tablet PC 2.0; wbx 1.0.0; Microsoft Outlook 14.0.7233; ms-office;", + }, + ], + "registry": [{"key": "MWnkl"}], + } diff --git a/tests_parsers/test_quickbind.py b/tests_parsers/test_quickbind.py index 91a2248dd70..19dac107ae0 100644 --- a/tests_parsers/test_quickbind.py +++ b/tests_parsers/test_quickbind.py @@ -3,8 +3,11 @@ # See the file 'docs/LICENSE' for copying permission. from modules.processing.parsers.CAPE.Quickbind import extract_config -from modules.processing.parsers.MACO.Quickbind import convert_to_MACO - +from contextlib import suppress +HAVE_MACO = False +with suppress(ImportError): + from modules.processing.parsers.MACO.Quickbind import convert_to_MACO + HAVE_MACO = True def test_quickbind(): with open("tests/data/malware/bfcb215f86fc4f8b4829f6ddd5acb118e80fb5bd977453fc7e8ef10a52fc83b7", "rb") as data: @@ -14,14 +17,15 @@ def test_quickbind(): "Mutex": ["15432a4d-34ca-4d0d-a4ac-04df9a373862"], "C2": ["185.49.69.41"], } - assert convert_to_MACO(conf).model_dump(exclude_defaults=True, exclude_none=True) == { - "family": "Quickbind", - "mutex": ["15432a4d-34ca-4d0d-a4ac-04df9a373862"], - "other": { - "Encryption Key": "24de21a8dc08434c", - "Mutex": ["15432a4d-34ca-4d0d-a4ac-04df9a373862"], - "C2": ["185.49.69.41"], - }, - "http": [{"hostname": "185.49.69.41", "usage": "c2"}], - "encryption": [{"key": "24de21a8dc08434c"}], - } + if HAVE_MACO: + assert convert_to_MACO(conf).model_dump(exclude_defaults=True, exclude_none=True) == { + "family": "Quickbind", + "mutex": ["15432a4d-34ca-4d0d-a4ac-04df9a373862"], + "other": { + "Encryption Key": "24de21a8dc08434c", + "Mutex": ["15432a4d-34ca-4d0d-a4ac-04df9a373862"], + "C2": ["185.49.69.41"], + }, + "http": [{"hostname": "185.49.69.41", "usage": "c2"}], + "encryption": [{"key": "24de21a8dc08434c"}], + } diff --git a/tests_parsers/test_redline.py b/tests_parsers/test_redline.py index 17ffaaa20cf..6e7712dde23 100644 --- a/tests_parsers/test_redline.py +++ b/tests_parsers/test_redline.py @@ -3,7 +3,12 @@ # See the file "docs/LICENSE" for copying permission. from modules.processing.parsers.CAPE.RedLine import extract_config -from modules.processing.parsers.MACO.RedLine import convert_to_MACO +from contextlib import suppress +HAVE_MACO = False +with suppress(ImportError): + from modules.processing.parsers.MACO.RedLine import convert_to_MACO + HAVE_MACO = True + def test_redline(): @@ -15,13 +20,14 @@ def test_redline(): "Botnet": "krast", "Key": "Formative", } - assert convert_to_MACO(conf).model_dump(exclude_defaults=True, exclude_none=True) == { - "family": "RedLine", - "other": { - "Authorization": "9059ea331e4599de3746df73ccb24514", - "C2": "77.91.68.68:19071", - "Botnet": "krast", - "Key": "Formative", - }, - "http": [{"hostname": "77.91.68.68", "port": 19071, "usage": "c2"}], - } + if HAVE_MACO: + assert convert_to_MACO(conf).model_dump(exclude_defaults=True, exclude_none=True) == { + "family": "RedLine", + "other": { + "Authorization": "9059ea331e4599de3746df73ccb24514", + "C2": "77.91.68.68:19071", + "Botnet": "krast", + "Key": "Formative", + }, + "http": [{"hostname": "77.91.68.68", "port": 19071, "usage": "c2"}], + } diff --git a/tests_parsers/test_smokeloader.py b/tests_parsers/test_smokeloader.py index cb7f4085a4e..52359c1dedf 100644 --- a/tests_parsers/test_smokeloader.py +++ b/tests_parsers/test_smokeloader.py @@ -1,13 +1,17 @@ from modules.processing.parsers.CAPE.SmokeLoader import extract_config -from modules.processing.parsers.MACO.SmokeLoader import convert_to_MACO - +from contextlib import suppress +HAVE_MACO = False +with suppress(ImportError): + from modules.processing.parsers.MACO.SmokeLoader import convert_to_MACO + HAVE_MACO = True def test_smokeloader(): with open("tests/data/malware/6929fff132c05ae7d348867f4ea77ba18f84fb8fae17d45dde3571c9e33f01f8", "rb") as data: conf = extract_config(data.read()) assert conf == {"C2s": ["http://host-file-host6.com/", "http://host-host-file8.com/"]} - assert convert_to_MACO(conf).model_dump(exclude_defaults=True, exclude_none=True) == { - "family": "SmokeLoader", - "other": {"C2s": ["http://host-file-host6.com/", "http://host-host-file8.com/"]}, - "http": [{"uri": "http://host-file-host6.com/", "usage": "c2"}, {"uri": "http://host-host-file8.com/", "usage": "c2"}], - } + if HAVE_MACO: + assert convert_to_MACO(conf).model_dump(exclude_defaults=True, exclude_none=True) == { + "family": "SmokeLoader", + "other": {"C2s": ["http://host-file-host6.com/", "http://host-host-file8.com/"]}, + "http": [{"uri": "http://host-file-host6.com/", "usage": "c2"}, {"uri": "http://host-host-file8.com/", "usage": "c2"}], + } diff --git a/tests_parsers/test_sparkrat.py b/tests_parsers/test_sparkrat.py index ba60ca225be..f655bf60132 100644 --- a/tests_parsers/test_sparkrat.py +++ b/tests_parsers/test_sparkrat.py @@ -1,5 +1,9 @@ from modules.processing.parsers.CAPE.SparkRAT import extract_config -from modules.processing.parsers.MACO.SparkRAT import convert_to_MACO +from contextlib import suppress +HAVE_MACO = False +with suppress(ImportError): + from modules.processing.parsers.MACO.SparkRAT import convert_to_MACO + HAVE_MACO = True def test_sparkrat(): @@ -13,16 +17,17 @@ def test_sparkrat(): "uuid": "8dc7e7d8f8576f3e55a00850b72887db", "key": "a1348fb8969ad7a9f85ac173c2027622135e52e0e6d94d10e6a81916a29648ac", } - assert convert_to_MACO(conf).model_dump(exclude_defaults=True, exclude_none=True) == { - "family": "SparkRAT", - "identifier": ["8dc7e7d8f8576f3e55a00850b72887db"], - "other": { - "secure": False, - "host": "67.217.62.106", - "port": 4443, - "path": "/", - "uuid": "8dc7e7d8f8576f3e55a00850b72887db", - "key": "a1348fb8969ad7a9f85ac173c2027622135e52e0e6d94d10e6a81916a29648ac", - }, - "http": [{"uri": "http://67.217.62.106:4443/", "hostname": "67.217.62.106", "port": 4443, "path": "/"}], - } + if HAVE_MACO: + assert convert_to_MACO(conf).model_dump(exclude_defaults=True, exclude_none=True) == { + "family": "SparkRAT", + "identifier": ["8dc7e7d8f8576f3e55a00850b72887db"], + "other": { + "secure": False, + "host": "67.217.62.106", + "port": 4443, + "path": "/", + "uuid": "8dc7e7d8f8576f3e55a00850b72887db", + "key": "a1348fb8969ad7a9f85ac173c2027622135e52e0e6d94d10e6a81916a29648ac", + }, + "http": [{"uri": "http://67.217.62.106:4443/", "hostname": "67.217.62.106", "port": 4443, "path": "/"}], + } diff --git a/tests_parsers/test_zloader.py b/tests_parsers/test_zloader.py index d9c0ef1f174..3c60247db86 100644 --- a/tests_parsers/test_zloader.py +++ b/tests_parsers/test_zloader.py @@ -3,7 +3,12 @@ # See the file 'docs/LICENSE' for copying permission. from modules.processing.parsers.CAPE.Zloader import extract_config -from modules.processing.parsers.MACO.Zloader import convert_to_MACO +from contextlib import suppress +HAVE_MACO = False +with suppress(ImportError): + from modules.processing.parsers.MACO.AgentTesla import convert_to_MACO + HAVE_MACO = True + def test_zloader(): @@ -15,14 +20,15 @@ def test_zloader(): "address": ["https://dem.businessdeep.com"], "Public key": "-----BEGIN PUBLIC KEY-----MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDKGAOWVkikqE7TyKIMtWI8dFsaleTaJNXMJNIPnRE/fGCzqrV+rtY3+ex4MCHEtq2Vwppthf0Rglv8OiWgKlerIN5P6NEyCfIsFYUMDfldQTF03VES8GBIvHq5SjlIz7lawuwfdjdEkaHfOmmu9srraftkI9gZO8WRQgY1uNdsXwIDAQAB-----END PUBLIC KEY-----", } - assert convert_to_MACO(conf).model_dump(exclude_defaults=True, exclude_none=True) == { - "family": "Zloader", - "campaign_id": ["M1"], - "other": { - "Botnet name": "Bing_Mod5", - "Campaign ID": "M1", - "address": ["https://dem.businessdeep.com"], - "Public key": "-----BEGIN PUBLIC KEY-----MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDKGAOWVkikqE7TyKIMtWI8dFsaleTaJNXMJNIPnRE/fGCzqrV+rtY3+ex4MCHEtq2Vwppthf0Rglv8OiWgKlerIN5P6NEyCfIsFYUMDfldQTF03VES8GBIvHq5SjlIz7lawuwfdjdEkaHfOmmu9srraftkI9gZO8WRQgY1uNdsXwIDAQAB-----END PUBLIC KEY-----", - }, - "http": [{"uri": "https://dem.businessdeep.com"}], - } + if HAVE_MACO: + assert convert_to_MACO(conf).model_dump(exclude_defaults=True, exclude_none=True) == { + "family": "Zloader", + "campaign_id": ["M1"], + "other": { + "Botnet name": "Bing_Mod5", + "Campaign ID": "M1", + "address": ["https://dem.businessdeep.com"], + "Public key": "-----BEGIN PUBLIC KEY-----MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDKGAOWVkikqE7TyKIMtWI8dFsaleTaJNXMJNIPnRE/fGCzqrV+rtY3+ex4MCHEtq2Vwppthf0Rglv8OiWgKlerIN5P6NEyCfIsFYUMDfldQTF03VES8GBIvHq5SjlIz7lawuwfdjdEkaHfOmmu9srraftkI9gZO8WRQgY1uNdsXwIDAQAB-----END PUBLIC KEY-----", + }, + "http": [{"uri": "https://dem.businessdeep.com"}], + } From eb1c4f46176b721b28f14e992cd196542bd62c56 Mon Sep 17 00:00:00 2001 From: GitHub Actions Date: Wed, 30 Oct 2024 13:10:16 +0000 Subject: [PATCH 022/121] style: Automatic code formatting --- tests_parsers/test_agenttesla.py | 4 +++- tests_parsers/test_asyncrat.py | 5 ++++- tests_parsers/test_aurorastealer.py | 5 ++++- tests_parsers/test_blackdropper.py | 6 ++++-- tests_parsers/test_bumblebee.py | 5 ++++- tests_parsers/test_carbanak.py | 5 ++++- tests_parsers/test_cobaltstrikebeacon.py | 6 ++++-- tests_parsers/test_darkgate.py | 5 ++++- tests_parsers/test_icedid.py | 5 ++++- tests_parsers/test_koiloader.py | 6 +++++- tests_parsers/test_latrodectus.py | 5 ++++- tests_parsers/test_lumma.py | 5 ++++- tests_parsers/test_nanocore.py | 5 ++++- tests_parsers/test_njrat.py | 5 ++++- tests_parsers/test_oyster.py | 5 ++++- tests_parsers/test_pikabot.py | 5 ++++- tests_parsers/test_quickbind.py | 6 +++++- tests_parsers/test_redline.py | 6 ++++-- tests_parsers/test_smokeloader.py | 11 +++++++++-- tests_parsers/test_sparkrat.py | 5 ++++- tests_parsers/test_zloader.py | 6 ++++-- 21 files changed, 90 insertions(+), 26 deletions(-) diff --git a/tests_parsers/test_agenttesla.py b/tests_parsers/test_agenttesla.py index 37050c3328e..b52cd064ce6 100644 --- a/tests_parsers/test_agenttesla.py +++ b/tests_parsers/test_agenttesla.py @@ -1,9 +1,11 @@ +from contextlib import suppress + from modules.processing.parsers.CAPE.AgentTesla import extract_config -from contextlib import suppress HAVE_MACO = False with suppress(ImportError): from modules.processing.parsers.MACO.AgentTesla import convert_to_MACO + HAVE_MACO = True diff --git a/tests_parsers/test_asyncrat.py b/tests_parsers/test_asyncrat.py index 8394d0af6d5..ee49867d95d 100644 --- a/tests_parsers/test_asyncrat.py +++ b/tests_parsers/test_asyncrat.py @@ -1,8 +1,11 @@ -from modules.processing.parsers.CAPE.AsyncRAT import extract_config from contextlib import suppress + +from modules.processing.parsers.CAPE.AsyncRAT import extract_config + HAVE_MACO = False with suppress(ImportError): from modules.processing.parsers.MACO.AsyncRAT import convert_to_MACO + HAVE_MACO = True diff --git a/tests_parsers/test_aurorastealer.py b/tests_parsers/test_aurorastealer.py index ddb2b157cb9..a09cc324614 100644 --- a/tests_parsers/test_aurorastealer.py +++ b/tests_parsers/test_aurorastealer.py @@ -1,8 +1,11 @@ -from modules.processing.parsers.CAPE.AuroraStealer import extract_config from contextlib import suppress + +from modules.processing.parsers.CAPE.AuroraStealer import extract_config + HAVE_MACO = False with suppress(ImportError): from modules.processing.parsers.MACO.AuroraStealer import convert_to_MACO + HAVE_MACO = True diff --git a/tests_parsers/test_blackdropper.py b/tests_parsers/test_blackdropper.py index d773329c4dc..cf8326f56cd 100644 --- a/tests_parsers/test_blackdropper.py +++ b/tests_parsers/test_blackdropper.py @@ -2,13 +2,15 @@ # This file is part of Cuckoo Sandbox - http://www.cuckoosandbox.org # See the file 'docs/LICENSE' for copying permission. -from modules.processing.parsers.CAPE.BlackDropper import extract_config from contextlib import suppress + +from modules.processing.parsers.CAPE.BlackDropper import extract_config + HAVE_MACO = False with suppress(ImportError): from modules.processing.parsers.MACO.BlackDropper import convert_to_MACO - HAVE_MACO = True + HAVE_MACO = True def test_blackdropper(): diff --git a/tests_parsers/test_bumblebee.py b/tests_parsers/test_bumblebee.py index 3ac5f6b57c7..c26509687a4 100644 --- a/tests_parsers/test_bumblebee.py +++ b/tests_parsers/test_bumblebee.py @@ -2,11 +2,14 @@ # This file is part of Cuckoo Sandbox - http://www.cuckoosandbox.org # See the file 'docs/LICENSE' for copying permission. -from modules.processing.parsers.CAPE.BumbleBee import extract_config from contextlib import suppress + +from modules.processing.parsers.CAPE.BumbleBee import extract_config + HAVE_MACO = False with suppress(ImportError): from modules.processing.parsers.MACO.BumbleBee import convert_to_MACO + HAVE_MACO = True diff --git a/tests_parsers/test_carbanak.py b/tests_parsers/test_carbanak.py index cb93c32bd58..bb0d512bccf 100644 --- a/tests_parsers/test_carbanak.py +++ b/tests_parsers/test_carbanak.py @@ -1,8 +1,11 @@ -from modules.processing.parsers.CAPE.Carbanak import extract_config from contextlib import suppress + +from modules.processing.parsers.CAPE.Carbanak import extract_config + HAVE_MACO = False with suppress(ImportError): from modules.processing.parsers.MACO.Carbanak import convert_to_MACO + HAVE_MACO = True diff --git a/tests_parsers/test_cobaltstrikebeacon.py b/tests_parsers/test_cobaltstrikebeacon.py index 1c6451afec6..12afcdd3677 100644 --- a/tests_parsers/test_cobaltstrikebeacon.py +++ b/tests_parsers/test_cobaltstrikebeacon.py @@ -2,13 +2,15 @@ # This file is part of Cuckoo Sandbox - http://www.cuckoosandbox.org # See the file 'docs/LICENSE' for copying permission. -from modules.processing.parsers.CAPE.CobaltStrikeBeacon import extract_config from contextlib import suppress + +from modules.processing.parsers.CAPE.CobaltStrikeBeacon import extract_config + HAVE_MACO = False with suppress(ImportError): from modules.processing.parsers.MACO.CobaltStrikeBeacon import convert_to_MACO - HAVE_MACO = True + HAVE_MACO = True def test_csb(): diff --git a/tests_parsers/test_darkgate.py b/tests_parsers/test_darkgate.py index 7a46843a84e..7040df6f51f 100644 --- a/tests_parsers/test_darkgate.py +++ b/tests_parsers/test_darkgate.py @@ -1,8 +1,11 @@ -from modules.processing.parsers.CAPE.DarkGate import extract_config from contextlib import suppress + +from modules.processing.parsers.CAPE.DarkGate import extract_config + HAVE_MACO = False with suppress(ImportError): from modules.processing.parsers.MACO.DarkGate import convert_to_MACO + HAVE_MACO = True diff --git a/tests_parsers/test_icedid.py b/tests_parsers/test_icedid.py index 4a8c93fc529..8b8b389a15d 100644 --- a/tests_parsers/test_icedid.py +++ b/tests_parsers/test_icedid.py @@ -1,8 +1,11 @@ -from modules.processing.parsers.CAPE.IcedIDLoader import extract_config from contextlib import suppress + +from modules.processing.parsers.CAPE.IcedIDLoader import extract_config + HAVE_MACO = False with suppress(ImportError): from modules.processing.parsers.MACO.IcedIDLoader import convert_to_MACO + HAVE_MACO = True diff --git a/tests_parsers/test_koiloader.py b/tests_parsers/test_koiloader.py index 0e9a3a01020..38a74bf700a 100644 --- a/tests_parsers/test_koiloader.py +++ b/tests_parsers/test_koiloader.py @@ -2,13 +2,17 @@ # This file is part of Cuckoo Sandbox - http://www.cuckoosandbox.org # See the file 'docs/LICENSE' for copying permission. -from modules.processing.parsers.CAPE.KoiLoader import extract_config from contextlib import suppress + +from modules.processing.parsers.CAPE.KoiLoader import extract_config + HAVE_MACO = False with suppress(ImportError): from modules.processing.parsers.MACO.KoiLoader import convert_to_MACO + HAVE_MACO = True + def test_koiloader(): with open("tests/data/malware/b462e3235c7578450b2b56a8aff875a3d99d22f6970a01db3ba98f7ecb6b01a0", "rb") as data: conf = extract_config(data.read()) diff --git a/tests_parsers/test_latrodectus.py b/tests_parsers/test_latrodectus.py index 31aab069bad..410bac0a9e2 100644 --- a/tests_parsers/test_latrodectus.py +++ b/tests_parsers/test_latrodectus.py @@ -2,11 +2,14 @@ # This file is part of Cuckoo Sandbox - http://www.cuckoosandbox.org # See the file 'docs/LICENSE' for copying permission. -from modules.processing.parsers.CAPE.Latrodectus import extract_config from contextlib import suppress + +from modules.processing.parsers.CAPE.Latrodectus import extract_config + HAVE_MACO = False with suppress(ImportError): from modules.processing.parsers.MACO.Latrodectus import convert_to_MACO + HAVE_MACO = True diff --git a/tests_parsers/test_lumma.py b/tests_parsers/test_lumma.py index c681636e01b..e341169bcdd 100644 --- a/tests_parsers/test_lumma.py +++ b/tests_parsers/test_lumma.py @@ -2,11 +2,14 @@ # This file is part of Cuckoo Sandbox - http://www.cuckoosandbox.org # See the file 'docs/LICENSE' for copying permission. -from modules.processing.parsers.CAPE.Lumma import extract_config from contextlib import suppress + +from modules.processing.parsers.CAPE.Lumma import extract_config + HAVE_MACO = False with suppress(ImportError): from modules.processing.parsers.MACO.Lumma import convert_to_MACO + HAVE_MACO = True diff --git a/tests_parsers/test_nanocore.py b/tests_parsers/test_nanocore.py index c0aeba7a3a4..af28b87d8ae 100644 --- a/tests_parsers/test_nanocore.py +++ b/tests_parsers/test_nanocore.py @@ -2,11 +2,14 @@ # This file is part of Cuckoo Sandbox - http://www.cuckoosandbox.org # See the file 'docs/LICENSE' for copying permission. -from modules.processing.parsers.CAPE.NanoCore import extract_config from contextlib import suppress + +from modules.processing.parsers.CAPE.NanoCore import extract_config + HAVE_MACO = False with suppress(ImportError): from modules.processing.parsers.MACO.NanoCore import convert_to_MACO + HAVE_MACO = True diff --git a/tests_parsers/test_njrat.py b/tests_parsers/test_njrat.py index 17729a6d9c1..106d9dd1662 100644 --- a/tests_parsers/test_njrat.py +++ b/tests_parsers/test_njrat.py @@ -2,11 +2,14 @@ # This file is part of Cuckoo Sandbox - http://www.cuckoosandbox.org # See the file 'docs/LICENSE' for copying permission. -from modules.processing.parsers.CAPE.Njrat import extract_config from contextlib import suppress + +from modules.processing.parsers.CAPE.Njrat import extract_config + HAVE_MACO = False with suppress(ImportError): from modules.processing.parsers.MACO.Njrat import convert_to_MACO + HAVE_MACO = True diff --git a/tests_parsers/test_oyster.py b/tests_parsers/test_oyster.py index d831764f686..85811e2f80e 100644 --- a/tests_parsers/test_oyster.py +++ b/tests_parsers/test_oyster.py @@ -2,11 +2,14 @@ # This file is part of Cuckoo Sandbox - http://www.cuckoosandbox.org # See the file 'docs/LICENSE' for copying permission. -from modules.processing.parsers.CAPE.Oyster import extract_config from contextlib import suppress + +from modules.processing.parsers.CAPE.Oyster import extract_config + HAVE_MACO = False with suppress(ImportError): from modules.processing.parsers.MACO.Oyster import convert_to_MACO + HAVE_MACO = True diff --git a/tests_parsers/test_pikabot.py b/tests_parsers/test_pikabot.py index 318b9f17a06..52d38194e55 100644 --- a/tests_parsers/test_pikabot.py +++ b/tests_parsers/test_pikabot.py @@ -2,11 +2,14 @@ # This file is part of Cuckoo Sandbox - http://www.cuckoosandbox.org # See the file 'docs/LICENSE' for copying permission. -from modules.processing.parsers.CAPE.PikaBot import extract_config from contextlib import suppress + +from modules.processing.parsers.CAPE.PikaBot import extract_config + HAVE_MACO = False with suppress(ImportError): from modules.processing.parsers.MACO.PikaBot import convert_to_MACO + HAVE_MACO = True diff --git a/tests_parsers/test_quickbind.py b/tests_parsers/test_quickbind.py index 19dac107ae0..094790ff831 100644 --- a/tests_parsers/test_quickbind.py +++ b/tests_parsers/test_quickbind.py @@ -2,13 +2,17 @@ # This file is part of Cuckoo Sandbox - http://www.cuckoosandbox.org # See the file 'docs/LICENSE' for copying permission. -from modules.processing.parsers.CAPE.Quickbind import extract_config from contextlib import suppress + +from modules.processing.parsers.CAPE.Quickbind import extract_config + HAVE_MACO = False with suppress(ImportError): from modules.processing.parsers.MACO.Quickbind import convert_to_MACO + HAVE_MACO = True + def test_quickbind(): with open("tests/data/malware/bfcb215f86fc4f8b4829f6ddd5acb118e80fb5bd977453fc7e8ef10a52fc83b7", "rb") as data: conf = extract_config(data.read()) diff --git a/tests_parsers/test_redline.py b/tests_parsers/test_redline.py index 6e7712dde23..8c455d06bac 100644 --- a/tests_parsers/test_redline.py +++ b/tests_parsers/test_redline.py @@ -2,13 +2,15 @@ # This file is part of Cuckoo Sandbox - http://www.cuckoosandbox.org # See the file "docs/LICENSE" for copying permission. -from modules.processing.parsers.CAPE.RedLine import extract_config from contextlib import suppress + +from modules.processing.parsers.CAPE.RedLine import extract_config + HAVE_MACO = False with suppress(ImportError): from modules.processing.parsers.MACO.RedLine import convert_to_MACO - HAVE_MACO = True + HAVE_MACO = True def test_redline(): diff --git a/tests_parsers/test_smokeloader.py b/tests_parsers/test_smokeloader.py index 52359c1dedf..216829dcd94 100644 --- a/tests_parsers/test_smokeloader.py +++ b/tests_parsers/test_smokeloader.py @@ -1,10 +1,14 @@ -from modules.processing.parsers.CAPE.SmokeLoader import extract_config from contextlib import suppress + +from modules.processing.parsers.CAPE.SmokeLoader import extract_config + HAVE_MACO = False with suppress(ImportError): from modules.processing.parsers.MACO.SmokeLoader import convert_to_MACO + HAVE_MACO = True + def test_smokeloader(): with open("tests/data/malware/6929fff132c05ae7d348867f4ea77ba18f84fb8fae17d45dde3571c9e33f01f8", "rb") as data: conf = extract_config(data.read()) @@ -13,5 +17,8 @@ def test_smokeloader(): assert convert_to_MACO(conf).model_dump(exclude_defaults=True, exclude_none=True) == { "family": "SmokeLoader", "other": {"C2s": ["http://host-file-host6.com/", "http://host-host-file8.com/"]}, - "http": [{"uri": "http://host-file-host6.com/", "usage": "c2"}, {"uri": "http://host-host-file8.com/", "usage": "c2"}], + "http": [ + {"uri": "http://host-file-host6.com/", "usage": "c2"}, + {"uri": "http://host-host-file8.com/", "usage": "c2"}, + ], } diff --git a/tests_parsers/test_sparkrat.py b/tests_parsers/test_sparkrat.py index f655bf60132..9e681b8efab 100644 --- a/tests_parsers/test_sparkrat.py +++ b/tests_parsers/test_sparkrat.py @@ -1,8 +1,11 @@ -from modules.processing.parsers.CAPE.SparkRAT import extract_config from contextlib import suppress + +from modules.processing.parsers.CAPE.SparkRAT import extract_config + HAVE_MACO = False with suppress(ImportError): from modules.processing.parsers.MACO.SparkRAT import convert_to_MACO + HAVE_MACO = True diff --git a/tests_parsers/test_zloader.py b/tests_parsers/test_zloader.py index 3c60247db86..dda237b9ef0 100644 --- a/tests_parsers/test_zloader.py +++ b/tests_parsers/test_zloader.py @@ -2,13 +2,15 @@ # This file is part of Cuckoo Sandbox - http://www.cuckoosandbox.org # See the file 'docs/LICENSE' for copying permission. -from modules.processing.parsers.CAPE.Zloader import extract_config from contextlib import suppress + +from modules.processing.parsers.CAPE.Zloader import extract_config + HAVE_MACO = False with suppress(ImportError): from modules.processing.parsers.MACO.AgentTesla import convert_to_MACO - HAVE_MACO = True + HAVE_MACO = True def test_zloader(): From 8c559dc83c52a34dca16dc540d4ef4c5185da079 Mon Sep 17 00:00:00 2001 From: doomedraven Date: Wed, 30 Oct 2024 16:09:09 +0100 Subject: [PATCH 023/121] Update human.py --- analyzer/windows/modules/auxiliary/human.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/analyzer/windows/modules/auxiliary/human.py b/analyzer/windows/modules/auxiliary/human.py index 095226251b2..c7fb4c8c519 100644 --- a/analyzer/windows/modules/auxiliary/human.py +++ b/analyzer/windows/modules/auxiliary/human.py @@ -71,6 +71,7 @@ "don't send", "don't save", "continue", + "connect", "unzip", "open", "close the program", @@ -115,6 +116,7 @@ DONT_CLICK_BUTTONS = ( # english "check online for a solution", + "don't ask me again for remote connections from this publisher", "don't run", "do not ask again until the next update is available", "cancel", From ebbc1fa6d678223e3226678cc5ffb2e8cb85a30b Mon Sep 17 00:00:00 2001 From: doomedraven Date: Wed, 30 Oct 2024 16:31:32 +0100 Subject: [PATCH 024/121] RKP as package --- lib/parsers_aux/__init__.py | 0 lib/parsers_aux/ratking/__init__.py | 211 ------------- .../ratking/config_parser_exception.py | 31 -- lib/parsers_aux/ratking/readme.md | 35 --- lib/parsers_aux/ratking/utils/__init__.py | 25 -- lib/parsers_aux/ratking/utils/config_item.py | 149 --------- lib/parsers_aux/ratking/utils/data_utils.py | 62 ---- .../ratking/utils/decryptors/__init__.py | 50 --- .../utils/decryptors/config_decryptor.py | 53 ---- .../decryptors/config_decryptor_aes_cbc.py | 290 ------------------ .../decryptors/config_decryptor_aes_ecb.py | 152 --------- .../config_decryptor_decrypt_xor.py | 121 -------- .../decryptors/config_decryptor_plaintext.py | 124 -------- .../config_decryptor_random_hardcoded.py | 96 ------ .../ratking/utils/dotnet_constants.py | 86 ------ .../ratking/utils/dotnetpe_payload.py | 199 ------------ modules/processing/parsers/CAPE/AsyncRAT.py | 2 +- modules/processing/parsers/CAPE/DCRat.py | 2 +- modules/processing/parsers/CAPE/QuasarRAT.py | 2 +- modules/processing/parsers/CAPE/VenomRAT.py | 2 +- modules/processing/parsers/CAPE/XWorm.py | 2 +- modules/processing/parsers/CAPE/XenoRAT.py | 2 +- poetry.lock | 25 +- pyproject.toml | 2 + 24 files changed, 32 insertions(+), 1691 deletions(-) delete mode 100644 lib/parsers_aux/__init__.py delete mode 100644 lib/parsers_aux/ratking/__init__.py delete mode 100644 lib/parsers_aux/ratking/config_parser_exception.py delete mode 100644 lib/parsers_aux/ratking/readme.md delete mode 100644 lib/parsers_aux/ratking/utils/__init__.py delete mode 100644 lib/parsers_aux/ratking/utils/config_item.py delete mode 100644 lib/parsers_aux/ratking/utils/data_utils.py delete mode 100644 lib/parsers_aux/ratking/utils/decryptors/__init__.py delete mode 100644 lib/parsers_aux/ratking/utils/decryptors/config_decryptor.py delete mode 100644 lib/parsers_aux/ratking/utils/decryptors/config_decryptor_aes_cbc.py delete mode 100644 lib/parsers_aux/ratking/utils/decryptors/config_decryptor_aes_ecb.py delete mode 100644 lib/parsers_aux/ratking/utils/decryptors/config_decryptor_decrypt_xor.py delete mode 100644 lib/parsers_aux/ratking/utils/decryptors/config_decryptor_plaintext.py delete mode 100644 lib/parsers_aux/ratking/utils/decryptors/config_decryptor_random_hardcoded.py delete mode 100644 lib/parsers_aux/ratking/utils/dotnet_constants.py delete mode 100644 lib/parsers_aux/ratking/utils/dotnetpe_payload.py diff --git a/lib/parsers_aux/__init__.py b/lib/parsers_aux/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/lib/parsers_aux/ratking/__init__.py b/lib/parsers_aux/ratking/__init__.py deleted file mode 100644 index a73ff2deaa7..00000000000 --- a/lib/parsers_aux/ratking/__init__.py +++ /dev/null @@ -1,211 +0,0 @@ -#!/usr/bin/env python3 -# -# rat_config_parser.py -# -# Author: jeFF0Falltrades -# -# Provides the primary functionality for parsing configurations from the -# AsyncRAT, DcRAT, QuasarRAT, VenomRAT, XWorm, XenoRAT, etc. RAT families -# -# MIT License -# -# Copyright (c) 2024 Jeff Archer -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in all -# copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -from logging import getLogger - -# from os.path import isfile -from re import DOTALL, compile, search -from typing import Any, Tuple - -from .config_parser_exception import ConfigParserException -from .utils import config_item -from .utils.decryptors import SUPPORTED_DECRYPTORS, ConfigDecryptor, IncompatibleDecryptorException -from .utils.dotnetpe_payload import DotNetPEPayload - -# from yara import Rules - - -logger = getLogger(__name__) - - -class RATConfigParser: - # Min and max number of items in a potential config section - _MIN_CONFIG_LEN_FLOOR = 5 - _MIN_CONFIG_LEN_CEILING = 9 - - # Pattern to find the VerifyHash() method - _PATTERN_VERIFY_HASH = compile(rb"\x7e.{3}\x04(?:\x6f.{3}\x0a){2}\x74.{3}\x01", DOTALL) - - # def __init__(self, file_path: str, yara_rule: Rules = None) -> None: - def __init__(self, file_data: bytes = None) -> None: - self.report = { - "config": {}, - } - try: - # Filled in _decrypt_and_decode_config() - self._incompatible_decryptors: list[int] = [] - try: - self._dnpp = DotNetPEPayload(file_data) - except Exception as e: - raise e - # self.report["sha256"] = self._dnpp.sha256 - # self.report["yara_possible_family"] = self._dnpp.yara_match - - # Assigned in _decrypt_and_decode_config() - self._decryptor: ConfigDecryptor = None - self.report["config"] = self._get_config() - self.report["key"] = ( - self._decryptor.key.hex() if self._decryptor is not None and self._decryptor.key is not None else "None" - ) - self.report["salt"] = ( - self._decryptor.salt.hex() if self._decryptor is not None and self._decryptor.salt is not None else "None" - ) - except Exception as e: - # self.report["config"] = f"Exception encountered for {file_path}: {e}" - self.report["config"] = f"Exception encountered: {e}" - - # Decrypts/decodes values from an encrypted config and returns the - # decrypted/decoded config - def _decrypt_and_decode_config(self, encrypted_config: bytes, min_config_len: int) -> dict[str, Any]: - decoded_config = {} - - for item_class in config_item.SUPPORTED_CONFIG_ITEMS: - item = item_class() - # Translate config Field RVAs to Field names - item_data = {self._dnpp.field_name_from_rva(k): v for k, v in item.parse_from(encrypted_config).items()} - - if len(item_data) > 0: - if type(item) is config_item.EncryptedStringConfigItem: - # Translate config value RVAs to string values - for k in item_data: - item_data[k] = self._dnpp.user_string_from_rva(item_data[k]) - - # Attempt to decrypt encrypted values - for decryptor in SUPPORTED_DECRYPTORS: - if decryptor in self._incompatible_decryptors: - continue - - if self._decryptor is None: - # Try to instantiate the selected decryptor - # Add to incompatible list and move on upon failure - try: - self._decryptor = decryptor(self._dnpp) - except IncompatibleDecryptorException as ide: - logger.debug(f"Decryptor incompatible {decryptor} : {ide}") - self._incompatible_decryptors.append(decryptor) - continue - try: - # Try to decrypt the encrypted strings - # Continue to next compatible decryptor on failure - item_data = self._decryptor.decrypt_encrypted_strings(item_data) - break - except Exception as e: - logger.debug(f"Decryption failed with decryptor {decryptor} : {e}") - self._decryptor = None - - if self._decryptor is None: - raise ConfigParserException("All decryptors failed") - - elif type(item) is config_item.ByteArrayConfigItem: - for k in item_data: - arr_size, arr_rva = item_data[k] - item_data[k] = self._dnpp.byte_array_from_size_and_rva(arr_size, arr_rva).hex() - - decoded_config.update(item_data) - - if len(decoded_config) < min_config_len: - raise ConfigParserException(f"Minimum threshold of config items not met: {len(decoded_config)}/{min_config_len}") - return decoded_config - - # Searches for the RAT configuration section, using the VerifyHash() marker - # or brute-force, returning the decrypted config on success - def _get_config(self) -> dict[str, Any]: - logger.debug("Extracting config...") - try: - config_start, decrypted_config = self._get_config_verify_hash_method() - except Exception: - logger.debug("VerifyHash() method failed; Attempting .cctor brute force...") - # If the VerifyHash() method does not work, move to brute-forcing - # static constructors - try: - config_start, decrypted_config = self._get_config_cctor_brute_force() - except Exception as e: - raise ConfigParserException(f"Could not identify config: {e}") - logger.debug(f"Config found at RVA {hex(config_start)}...") - return decrypted_config - - # Attempts to retrieve the config via brute-force, looking through every - # static constructor (.cctor) and attempting to decode/decrypt a valid - # config from that constructor, returning the config RVA and decrypted - # config on success - def _get_config_cctor_brute_force(self) -> Tuple[int, dict[str, Any]]: - candidates = self._dnpp.methods_from_name(".cctor") - if len(candidates) == 0: - raise ConfigParserException("No .cctor method could be found") - - # For each .cctor method, map its RVA and body (in raw bytes) - candidate_cctor_data = {method.rva: self._dnpp.method_body_from_method(method) for method in candidates} - - config_start, decrypted_config = None, None - # Start at our ceiling value for number of config items - min_config_len = self._MIN_CONFIG_LEN_CEILING - - while decrypted_config is None and min_config_len >= self._MIN_CONFIG_LEN_FLOOR: - for method_rva, method_body in candidate_cctor_data.items(): - logger.debug(f"Attempting brute force at .cctor method at {hex(method_rva)}") - try: - config_start, decrypted_config = ( - method_rva, - self._decrypt_and_decode_config(method_body, min_config_len), - ) - break - except Exception as e: - logger.debug(f"Brute force failed for method at {hex(method_rva)}: {e}") - continue - # Reduce the minimum config length until we reach our floor - min_config_len -= 1 - - if decrypted_config is None: - raise ConfigParserException("No valid configuration could be parsed from any .cctor methods") - return config_start, decrypted_config - - # Attempts to retrieve the config via looking for a config section preceded - # by the VerifyHash() method typically found in a Settings module, - # returning the config RVA and decrypted config on success - def _get_config_verify_hash_method(self) -> Tuple[int, dict[str, Any]]: - # Identify the VerifyHash() Method code - verify_hash_hit = search(self._PATTERN_VERIFY_HASH, self._dnpp.data) - if verify_hash_hit is None: - raise ConfigParserException("Could not identify VerifyHash() marker") - - # Reverse the hit to find the VerifyHash() method, then grab the - # subsequent function - config_method = self._dnpp.method_from_instruction_offset(verify_hash_hit.start(), 1) - encrypted_config = self._dnpp.method_body_from_method(config_method) - min_config_len = self._MIN_CONFIG_LEN_CEILING - while True: - try: - decrypted_config = self._decrypt_and_decode_config(encrypted_config, min_config_len) - return config_method.rva, decrypted_config - except Exception as e: - # Reduce the minimum config length until we reach our floor - if min_config_len < self._MIN_CONFIG_LEN_FLOOR: - raise e - min_config_len -= 1 diff --git a/lib/parsers_aux/ratking/config_parser_exception.py b/lib/parsers_aux/ratking/config_parser_exception.py deleted file mode 100644 index 2b8c1b06282..00000000000 --- a/lib/parsers_aux/ratking/config_parser_exception.py +++ /dev/null @@ -1,31 +0,0 @@ -#!/usr/bin/env python3 -# -# config_parser_exception.py -# -# Author: jeFF0Falltrades -# -# A simple custom Exception class for use with configuration parsing actions -# -# MIT License -# -# Copyright (c) 2024 Jeff Archer -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in all -# copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -class ConfigParserException(Exception): - pass diff --git a/lib/parsers_aux/ratking/readme.md b/lib/parsers_aux/ratking/readme.md deleted file mode 100644 index 28fc18ea444..00000000000 --- a/lib/parsers_aux/ratking/readme.md +++ /dev/null @@ -1,35 +0,0 @@ -All works here is done by https://github.com/jeFF0Falltrades/rat_king_parser - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/lib/parsers_aux/ratking/utils/__init__.py b/lib/parsers_aux/ratking/utils/__init__.py deleted file mode 100644 index 716cb99880a..00000000000 --- a/lib/parsers_aux/ratking/utils/__init__.py +++ /dev/null @@ -1,25 +0,0 @@ -#!/usr/bin/env python3 -# -# __init__.py -# -# Author: jeFF0Falltrades -# -# Copyright (c) 2024 Jeff Archer -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in all -# copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. diff --git a/lib/parsers_aux/ratking/utils/config_item.py b/lib/parsers_aux/ratking/utils/config_item.py deleted file mode 100644 index e466c018b5e..00000000000 --- a/lib/parsers_aux/ratking/utils/config_item.py +++ /dev/null @@ -1,149 +0,0 @@ -#!/usr/bin/env python3 -# -# config_item.py -# -# Author: jeFF0Falltrades -# -# Provides a utility class for parsing field names and values of various types -# from raw RAT config data -# -# MIT License -# -# Copyright (c) 2024 Jeff Archer -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in all -# copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -from abc import ABC, abstractmethod -from logging import getLogger -from re import DOTALL, compile, findall -from typing import Any, Tuple - -from .data_utils import bytes_to_int -from .dotnet_constants import OPCODE_LDC_I4_0, SpecialFolder - -logger = getLogger(__name__) - - -# Provides an abstract class for config items -class ConfigItem(ABC): - def __init__(self, label: str, pattern: bytes) -> None: - self._label = label - self._pattern = compile(pattern, flags=DOTALL) - - # Should be overridden by children to provide a meaningful value - @abstractmethod - def _derive_item_value(self) -> Any: - pass - - # Derives config Field RVAs and values from data using the specified - # ConfigItem's pattern - def parse_from(self, data: bytes) -> dict[int, Any]: - logger.debug(f"Parsing {self._label} values from data...") - fields = {} - raw_data = findall(self._pattern, data) - found_items = 0 - for obj, bytes_rva in raw_data: - try: - field_value = self._derive_item_value(obj) - field_rva = bytes_to_int(bytes_rva) - except Exception: - logger.debug(f"Could not parse value from {obj} at {hex(bytes_rva)}") - continue - if field_rva not in fields: - fields[field_rva] = field_value - found_items += 1 - else: - logger.debug(f"Overlapping Field RVAs detected in config at {hex(field_rva)}") - logger.debug(f"Parsed {found_items} {self._label} values") - return fields - - -class BoolConfigItem(ConfigItem): - def __init__(self) -> None: - super().__init__("boolean", b"(\x16|\x17)\x80(.{3}\x04)") - - # Boolean values are derived by examing if the opcode is "ldc.i4.0" (False) - # or "ldc.i4.1" (True) - def _derive_item_value(self, opcode: bytes) -> bool: - return bool(bytes_to_int(opcode) - bytes_to_int(OPCODE_LDC_I4_0)) - - -class ByteArrayConfigItem(ConfigItem): - def __init__(self) -> None: - super().__init__( - "byte array", - rb"\x1f(.\x8d.{3}\x01\x25\xd0.{3}\x04)\x28.{3}\x0a\x80(.{3}\x04)", - ) - - # Byte array size and RVA are returned, as these are needed to - # extract the value of the bytes from the payload - def _derive_item_value(self, byte_data: bytes) -> Tuple[int, int]: - arr_size = byte_data[0] - arr_rva = bytes_to_int(byte_data[-4:]) - return (arr_size, arr_rva) - - -class IntConfigItem(ConfigItem): - def __init__(self) -> None: - super().__init__("int", b"(\x20.{4}|[\x18-\x1e])\x80(.{3}\x04)") - - def _derive_item_value(self, int_bytes: bytes) -> int: - # If single byte, must be value 2-8, represented by opcodes 0x18-0x1e - # Subtract 0x16 to get the int value, e.g.: - # ldc.i4.8 == 0x1e - 0x16 == 8 - if len(int_bytes) == 1: - return bytes_to_int(int_bytes) - 0x16 - # Else, look for which int was loaded by "ldc.i4" - return bytes_to_int(int_bytes[1:]) - - -class NullConfigItem(ConfigItem): - def __init__(self) -> None: - super().__init__("null", b"(\x14\x80)(.{3}\x04)") - - # If "ldnull" is being used, simply return "null" - def _derive_item_value(self, _: bytes) -> str: - return "null" - - -class SpecialFolderConfigItem(ConfigItem): - def __init__(self) -> None: - super().__init__("special folder", b"\x1f(.)\x80(.{3}\x04)") - - # Translates SpecialFolder ID to name - def _derive_item_value(self, folder_id: bytes) -> str: - return SpecialFolder(bytes_to_int(folder_id)).name - - -class EncryptedStringConfigItem(ConfigItem): - def __init__(self) -> None: - super().__init__("encrypted string", b"\x72(.{3}\x70)\x80(.{3}\x04)") - - # Returns the encrypted string's RVA - def _derive_item_value(self, enc_str_rva: bytes) -> int: - return bytes_to_int(enc_str_rva) - - -SUPPORTED_CONFIG_ITEMS = [ - BoolConfigItem, - ByteArrayConfigItem, - IntConfigItem, - NullConfigItem, - SpecialFolderConfigItem, - EncryptedStringConfigItem, -] diff --git a/lib/parsers_aux/ratking/utils/data_utils.py b/lib/parsers_aux/ratking/utils/data_utils.py deleted file mode 100644 index 1f0ec88cd02..00000000000 --- a/lib/parsers_aux/ratking/utils/data_utils.py +++ /dev/null @@ -1,62 +0,0 @@ -#!/usr/bin/env python3 -# -# data_utils.py -# -# Author: jeFF0Falltrades -# -# Provides various utility functions for working with binary data -# -# MIT License -# -# Copyright (c) 2024 Jeff Archer -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in all -# copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -from ..config_parser_exception import ConfigParserException - - -# Converts a bytes object to an int object using the specified byte order -def bytes_to_int(bytes: bytes, order: str = "little") -> int: - try: - return int.from_bytes(bytes, byteorder=order) - except Exception: - raise ConfigParserException(f"Error parsing int from value: {bytes}") - - -# Decodes a bytes object to a Unicode string, using UTF-16LE for byte values -# with null bytes still embedded in them, and UTF-8 for all other values -def decode_bytes(byte_str: bytes | str) -> str: - if isinstance(byte_str, str): - return byte_str.strip() - result = None - try: - if b"\x00" in byte_str: - result = byte_str.decode("utf-16le") - else: - result = byte_str.decode("utf-8") - except Exception: - raise ConfigParserException(f"Error decoding bytes object to Unicode: {byte_str}") - return result - - -# Converts an int to a bytes object, with the specified length and order -def int_to_bytes(int: int, length: int = 4, order: str = "little") -> bytes: - try: - return int.to_bytes(length, order) - except Exception: - raise ConfigParserException(f"Error parsing bytes from value: {int}") diff --git a/lib/parsers_aux/ratking/utils/decryptors/__init__.py b/lib/parsers_aux/ratking/utils/decryptors/__init__.py deleted file mode 100644 index a340a598f31..00000000000 --- a/lib/parsers_aux/ratking/utils/decryptors/__init__.py +++ /dev/null @@ -1,50 +0,0 @@ -#!/usr/bin/env python3 -# -# __init__.py -# -# Author: jeFF0Falltrades -# -# Copyright (c) 2024 Jeff Archer -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in all -# copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -from .config_decryptor import ConfigDecryptor, IncompatibleDecryptorException -from .config_decryptor_aes_cbc import ConfigDecryptorAESCBC -from .config_decryptor_aes_ecb import ConfigDecryptorAESECB -from .config_decryptor_decrypt_xor import ConfigDecryptorDecryptXOR -from .config_decryptor_plaintext import ConfigDecryptorPlaintext -from .config_decryptor_random_hardcoded import ConfigDecryptorRandomHardcoded - -__all__ = [ - ConfigDecryptor, - IncompatibleDecryptorException, - ConfigDecryptorAESCBC, - ConfigDecryptorAESECB, - ConfigDecryptorDecryptXOR, - ConfigDecryptorRandomHardcoded, - ConfigDecryptorPlaintext, -] - -# ConfigDecryptorPlaintext should always be the last fallthrough case -SUPPORTED_DECRYPTORS = [ - ConfigDecryptorAESCBC, - ConfigDecryptorAESECB, - ConfigDecryptorDecryptXOR, - ConfigDecryptorRandomHardcoded, - ConfigDecryptorPlaintext, -] diff --git a/lib/parsers_aux/ratking/utils/decryptors/config_decryptor.py b/lib/parsers_aux/ratking/utils/decryptors/config_decryptor.py deleted file mode 100644 index 8b4827d38b3..00000000000 --- a/lib/parsers_aux/ratking/utils/decryptors/config_decryptor.py +++ /dev/null @@ -1,53 +0,0 @@ -#!/usr/bin/env python3 -# -# config_decryptor.py -# -# Author: jeFF0Falltrades -# -# Provides a simple abstract base class for different types of config decryptors -# -# MIT License -# -# Copyright (c) 2024 Jeff Archer -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in all -# copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -from abc import ABC, abstractmethod -from logging import getLogger - -from ..dotnetpe_payload import DotNetPEPayload - -logger = getLogger(__name__) - - -# Custom Exception to denote that a decryptor is incompatible with a payload -class IncompatibleDecryptorException(Exception): - pass - - -class ConfigDecryptor(ABC): - def __init__(self, payload: DotNetPEPayload) -> None: - self.key: bytes | str = None - self._payload = payload - self.salt: bytes = None - - # Abstract method to take in a map representing a configuration of config - # Field names and values and return a decoded/decrypted configuration - @abstractmethod - def decrypt_encrypted_strings(self, encrypted_strings: dict[str, str]) -> dict[str, list[str] | str]: - pass diff --git a/lib/parsers_aux/ratking/utils/decryptors/config_decryptor_aes_cbc.py b/lib/parsers_aux/ratking/utils/decryptors/config_decryptor_aes_cbc.py deleted file mode 100644 index 886a804eb68..00000000000 --- a/lib/parsers_aux/ratking/utils/decryptors/config_decryptor_aes_cbc.py +++ /dev/null @@ -1,290 +0,0 @@ -#!/usr/bin/env python3 -# -# config_decryptor_aes_cbc.py -# -# Author: jeFF0Falltrades -# -# Provides a custom AES decryptor for RAT payloads utilizing CBC mode -# -# Example Hash: 6b99acfa5961591c39b3f889cf29970c1dd48ddb0e274f14317940cf279a4412 -# -# MIT License -# -# Copyright (c) 2024 Jeff Archer -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in all -# copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -from base64 import b64decode -from logging import getLogger -from re import DOTALL, compile, escape, search -from typing import Tuple - -from cryptography.hazmat.backends import default_backend -from cryptography.hazmat.primitives.ciphers import Cipher -from cryptography.hazmat.primitives.ciphers.algorithms import AES -from cryptography.hazmat.primitives.ciphers.modes import CBC -from cryptography.hazmat.primitives.hashes import SHA1 -from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC -from cryptography.hazmat.primitives.padding import PKCS7 - -from ...config_parser_exception import ConfigParserException -from ..data_utils import bytes_to_int, decode_bytes, int_to_bytes -from ..dotnet_constants import OPCODE_LDSTR, OPCODE_LDTOKEN -from ..dotnetpe_payload import DotNetPEPayload -from .config_decryptor import ConfigDecryptor, IncompatibleDecryptorException - -logger = getLogger(__name__) - - -class ConfigDecryptorAESCBC(ConfigDecryptor): - # Minimum length of valid ciphertext - _MIN_CIPHERTEXT_LEN = 48 - - # Patterns for identifying AES metadata - _PATTERN_AES_KEY_AND_BLOCK_SIZE = compile(b"[\x06-\x09]\x20(.{4})\x6f.{4}[\x06-\x09]\x20(.{4})", DOTALL) - # Do not compile in-line replacement patterns - _PATTERN_AES_KEY_BASE = b"(.{3}\x04).%b" - _PATTERN_AES_SALT_INIT = b"\x80%b\x2a" - _PATTERN_AES_SALT_ITER = compile(b"[\x02-\x05]\x7e(.{4})\x20(.{4})\x73", DOTALL) - - def __init__(self, payload: DotNetPEPayload) -> None: - super().__init__(payload) - self._block_size: int = None - self._iterations: int = None - self._key_candidates: list[bytes] = None - self._key_size: int = None - self._key_rva: int = None - try: - self._get_aes_metadata() - except Exception as e: - raise IncompatibleDecryptorException(e) - - # Given an initialization vector and ciphertext, creates a Cipher - # object with the AES key and specified IV and decrypts the ciphertext - def _decrypt(self, iv: bytes, ciphertext: bytes) -> bytes: - logger.debug(f"Decrypting {ciphertext} with key {self.key.hex()} and IV {iv.hex()}...") - aes_cipher = Cipher(AES(self.key), CBC(iv), backend=default_backend()) - decryptor = aes_cipher.decryptor() - # Use a PKCS7 unpadder to remove padding from decrypted value - # https://cryptography.io/en/latest/hazmat/primitives/padding/ - unpadder = PKCS7(self._block_size).unpadder() - - try: - padded_text = decryptor.update(ciphertext) + decryptor.finalize() - unpadded_text = unpadder.update(padded_text) + unpadder.finalize() - except Exception as e: - raise ConfigParserException( - f"Error decrypting ciphertext {ciphertext} with IV {iv.hex()} and key {self.key.hex()} : {e}" - ) - - logger.debug(f"Decryption result: {unpadded_text}") - return unpadded_text - - # Derives AES passphrase candidates from a config - # - # If a passphrase is base64-encoded, both its raw value and decoded value - # will be added as candidates - def _derive_aes_passphrase_candidates(self, key_val: str) -> list[bytes]: - passphrase_candidates = [key_val.encode()] - try: - passphrase_candidates.append(b64decode(key_val)) - except Exception: - pass - logger.debug(f"AES passphrase candidates found: {passphrase_candidates}") - return passphrase_candidates - - # Decrypts encrypted config values with the provided cipher data - def decrypt_encrypted_strings(self, encrypted_strings: dict[str, str]) -> dict[str, str]: - logger.debug("Decrypting encrypted strings...") - if self._key_candidates is None: - self._key_candidates = self._get_aes_key_candidates(encrypted_strings) - - decrypted_config_strings = {} - for k, v in encrypted_strings.items(): - # Leave empty strings as they are - if len(v) == 0: - logger.debug(f"Key: {k}, Value: {v}") - decrypted_config_strings[k] = v - continue - - # Check if base64-encoded string - b64_exception = False - try: - decoded_val = b64decode(v) - except Exception: - b64_exception = True - # If it was not base64-encoded, or if it is less than our min length - # for ciphertext, leave the value as it is - if b64_exception or len(decoded_val) < self._MIN_CIPHERTEXT_LEN: - logger.debug(f"Key: {k}, Value: {v}") - decrypted_config_strings[k] = v - continue - - # Otherwise, extract the IV from the 16 bytes after the HMAC - # (first 32 bytes) and the ciphertext from the rest of the data - # after the IV, and run the decryption - iv, ciphertext = decoded_val[32:48], decoded_val[48:] - result, last_exc = None, None - key_idx = 0 - # Run through key candidates until suitable one found or failure - while result is None and key_idx < len(self._key_candidates): - try: - self.key = self._key_candidates[key_idx] - key_idx += 1 - result = decode_bytes(self._decrypt(iv, ciphertext)) - except ConfigParserException as e: - last_exc = e - - if result is None: - logger.debug(f"Decryption failed for item {v}: {last_exc}; Leaving as original value...") - result = v - - logger.debug(f"Key: {k}, Value: {result}") - decrypted_config_strings[k] = result - - logger.debug("Successfully decrypted strings") - return decrypted_config_strings - - # Extracts AES key candidates from the payload - def _get_aes_key_candidates(self, encrypted_strings: dict[str, str]) -> list[bytes]: - logger.debug("Extracting AES key candidates...") - keys = [] - - # Use the key Field name to index into our existing config - key_raw_value = encrypted_strings[self._payload.field_name_from_rva(self._key_rva)] - passphrase_candidates = self._derive_aes_passphrase_candidates(key_raw_value) - - for candidate in passphrase_candidates: - try: - # The backend parameter is optional in newer versions of the - # cryptography library, but we keep it here for compatibility - kdf = PBKDF2HMAC( - SHA1(), - length=self._key_size, - salt=self.salt, - iterations=self._iterations, - backend=default_backend(), - ) - keys.append(kdf.derive(candidate)) - logger.debug(f"AES key derived: {keys[-1]}") - except Exception: - continue - - if len(keys) == 0: - raise ConfigParserException(f"Could not derive key from passphrase candidates: {passphrase_candidates}") - return keys - - # Extracts the AES key and block size from the payload - def _get_aes_key_and_block_size(self) -> Tuple[int, int]: - logger.debug("Extracting AES key and block size...") - hit = search(self._PATTERN_AES_KEY_AND_BLOCK_SIZE, self._payload.data) - if hit is None: - raise ConfigParserException("Could not extract AES key or block size") - - # Convert key size from bits to bytes by dividing by 8 - # Note use of // instead of / to ensure integer output, not float - key_size = bytes_to_int(hit.groups()[0]) // 8 - block_size = bytes_to_int(hit.groups()[1]) - - logger.debug(f"Found key size {key_size} and block size {block_size}") - return key_size, block_size - - # Given an offset to an instruction within the Method that sets up the - # Cipher, extracts the AES key RVA from the payload - def _get_aes_key_rva(self, metadata_ins_offset: int) -> int: - logger.debug("Extracting AES key RVA...") - - # Get the RVA of the method that sets up AES256 metadata - metadata_method_token = self._payload.method_from_instruction_offset(metadata_ins_offset, by_token=True).token - - # Insert this RVA into the KEY_BASE pattern to find where the AES key - # is initialized - key_hit = search( - self._PATTERN_AES_KEY_BASE % escape(int_to_bytes(metadata_method_token)), - self._payload.data, - DOTALL, - ) - if key_hit is None: - raise ConfigParserException("Could not find AES key pattern") - - key_rva = bytes_to_int(key_hit.groups()[0]) - logger.debug(f"AES key RVA: {hex(key_rva)}") - return key_rva - - # Identifies the initialization of the AES256 object in the payload and - # sets the necessary values needed for decryption - def _get_aes_metadata(self) -> None: - logger.debug("Extracting AES metadata...") - metadata = search(self._PATTERN_AES_SALT_ITER, self._payload.data) - if metadata is None: - raise ConfigParserException("Could not identify AES metadata") - logger.debug(f"AES metadata found at offset {hex(metadata.start())}") - - self._key_size, self._block_size = self._get_aes_key_and_block_size() - - logger.debug("Extracting AES iterations...") - self._iterations = bytes_to_int(metadata.groups()[1]) - logger.debug(f"Found AES iteration number of {self._iterations}") - - self.salt = self._get_aes_salt(metadata.groups()[0]) - self._key_rva = self._get_aes_key_rva(metadata.start()) - - # Extracts the AES salt from the payload, accounting for both hardcoded - # salt byte arrays, and salts derived from hardcoded strings - def _get_aes_salt(self, salt_rva: int) -> bytes: - logger.debug("Extracting AES salt value...") - - # Use % to insert our salt RVA into our match pattern - # This pattern will then find the salt initialization ops, - # specifically: - # - # stsfld uint8[] Client.Algorithm.Aes256::Salt - # ret - aes_salt_initialization = self._payload.data.find(self._PATTERN_AES_SALT_INIT % escape(salt_rva)) - if aes_salt_initialization == -1: - raise ConfigParserException("Could not identify AES salt initialization") - - # Look at the opcode used to initialize the salt to decide how to - # proceed with extracting the salt value (start of pattern - 10 bytes) - salt_op_offset = aes_salt_initialization - 10 - # Need to use bytes([int]) here to properly convert from int to byte - # string for our comparison below - salt_op = bytes([self._payload.data[salt_op_offset]]) - - # Get the salt RVA from the 4 bytes following the initialization op - salt_strings_rva_packed = self._payload.data[salt_op_offset + 1 : salt_op_offset + 5] - salt_strings_rva = bytes_to_int(salt_strings_rva_packed) - - # If the op is a ldstr op, just get the bytes value of the string being - # used to initialize the salt - if salt_op == OPCODE_LDSTR: - salt_encoded = self._payload.user_string_from_rva(salt_strings_rva) - # We use decode_bytes() here to get the salt string without any - # null bytes (because it's stored as UTF-16LE), then convert it - # back to bytes - salt = decode_bytes(salt_encoded).encode() - # If the op is a ldtoken (0xd0) operation, we need to get the salt - # byte array value from the FieldRVA table - elif salt_op == OPCODE_LDTOKEN: - salt_size = self._payload.data[salt_op_offset - 7] - salt = self._payload.byte_array_from_size_and_rva(salt_size, salt_strings_rva) - else: - raise ConfigParserException(f"Unknown salt opcode found: {salt_op.hex()}") - - logger.debug(f"Found salt value: {salt.hex()}") - return salt diff --git a/lib/parsers_aux/ratking/utils/decryptors/config_decryptor_aes_ecb.py b/lib/parsers_aux/ratking/utils/decryptors/config_decryptor_aes_ecb.py deleted file mode 100644 index 668c18de4e6..00000000000 --- a/lib/parsers_aux/ratking/utils/decryptors/config_decryptor_aes_ecb.py +++ /dev/null @@ -1,152 +0,0 @@ -#!/usr/bin/env python3 -# -# config_decryptor_aes_ecb.py -# -# Author: jeFF0Falltrades -# -# Provides a custom AES decryptor for RAT payloads utilizing ECB mode -# -# Example Hash: d5028e10a756f2df677f32ebde105d7de8df37e253c431837c8f810260f4428e -# -# MIT License -# -# Copyright (c) 2024 Jeff Archer -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in all -# copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -from base64 import b64decode -from hashlib import md5 -from logging import getLogger -from re import DOTALL, compile, search - -from cryptography.hazmat.backends import default_backend -from cryptography.hazmat.primitives.ciphers import Cipher -from cryptography.hazmat.primitives.ciphers.algorithms import AES -from cryptography.hazmat.primitives.ciphers.modes import ECB -from cryptography.hazmat.primitives.padding import PKCS7 - -from ...config_parser_exception import ConfigParserException -from ..data_utils import bytes_to_int, decode_bytes -from ..dotnetpe_payload import DotNetPEPayload -from .config_decryptor import ConfigDecryptor, IncompatibleDecryptorException - -logger = getLogger(__name__) - - -class ConfigDecryptorAESECB(ConfigDecryptor): - # MD5 hash pattern used to detect AES key - _PATTERN_MD5_HASH = compile(rb"\x7e(.{3}\x04)\x28.{3}\x06\x6f", DOTALL) - - def __init__(self, payload: DotNetPEPayload) -> None: - super().__init__(payload) - try: - self._aes_key_rva = self._get_aes_key_rva() - except Exception as e: - raise IncompatibleDecryptorException(e) - - # Given ciphertext, creates a Cipher object with the AES key and decrypts - # the ciphertext - def _decrypt(self, ciphertext: bytes) -> bytes: - logger.debug(f"Decrypting {ciphertext} with key {self.key.hex()}...") - aes_cipher = Cipher(AES(self.key), ECB(), backend=default_backend()) - decryptor = aes_cipher.decryptor() - unpadder = PKCS7(AES.block_size).unpadder() - # Use a PKCS7 unpadder to remove padding from decrypted value - # https://cryptography.io/en/latest/hazmat/primitives/padding/ - unpadder = PKCS7(AES.block_size).unpadder() - - try: - padded_text = decryptor.update(ciphertext) + decryptor.finalize() - unpadded_text = unpadder.update(padded_text) + unpadder.finalize() - except Exception as e: - raise ConfigParserException(f"Error decrypting ciphertext {ciphertext} with key {self.key.hex()}: {e}") - - logger.debug(f"Decryption result: {unpadded_text}") - return unpadded_text - - # Decrypts encrypted config values with the provided cipher data - def decrypt_encrypted_strings(self, encrypted_strings: dict[str, str]) -> dict[str, str]: - logger.debug("Decrypting encrypted strings...") - - if self.key is None: - try: - raw_key_field = self._payload.field_name_from_rva(self._aes_key_rva) - self.key = self._derive_aes_key(encrypted_strings[raw_key_field]) - except Exception as e: - raise ConfigParserException(f"Failed to derive AES key: {e}") - - decrypted_config_strings = {} - for k, v in encrypted_strings.items(): - # Leave empty strings as they are - if len(v) == 0: - logger.debug(f"Key: {k}, Value: {v}") - decrypted_config_strings[k] = v - continue - - # Check if base64-encoded string - b64_exception = False - try: - decoded_val = b64decode(v) - except Exception: - b64_exception = True - # If it was not base64-encoded, leave the value as it is - if b64_exception: - logger.debug(f"Key: {k}, Value: {v}") - decrypted_config_strings[k] = v - continue - - ciphertext = decoded_val - result, last_exc = None, None - try: - result = decode_bytes(self._decrypt(ciphertext)) - except ConfigParserException as e: - last_exc = e - - if result is None: - logger.debug(f"Decryption failed for item {v}: {last_exc}") - result = v - - logger.debug(f"Key: {k}, Value: {result}") - decrypted_config_strings[k] = result - - logger.debug("Successfully decrypted strings") - return decrypted_config_strings - - # Given the raw bytes that will become the key value, derives the AES key - def _derive_aes_key(self, key_unhashed: str) -> bytes: - # Generate the MD5 hash - md5_hash = md5() - md5_hash.update(key_unhashed.encode("utf-8")) - md5_digest = md5_hash.digest() - - # Key is a 32-byte value made up of the MD5 hash overlaying itself, - # tailed with one null byte - key = md5_digest[:15] + md5_digest[:16] + b"\x00" - logger.debug(f"AES key derived: {key}") - return key - - # Extracts the AES key RVA from the payload - def _get_aes_key_rva(self) -> int: - logger.debug("Extracting AES key value...") - key_hit = search(self._PATTERN_MD5_HASH, self._payload.data) - if key_hit is None: - raise ConfigParserException("Could not find AES key pattern") - - key_rva = bytes_to_int(key_hit.groups()[0]) - logger.debug(f"AES key RVA: {hex(key_rva)}") - return key_rva diff --git a/lib/parsers_aux/ratking/utils/decryptors/config_decryptor_decrypt_xor.py b/lib/parsers_aux/ratking/utils/decryptors/config_decryptor_decrypt_xor.py deleted file mode 100644 index 7ea52618ceb..00000000000 --- a/lib/parsers_aux/ratking/utils/decryptors/config_decryptor_decrypt_xor.py +++ /dev/null @@ -1,121 +0,0 @@ -#!/usr/bin/env python3 -# -# config_decryptor_decrypt_xor.py -# -# Author: jeFF0Falltrades -# -# Provides a custom decryptor for RAT payloads utilizing the DecryptXOR -# method of embeddeding config strings -# -# Example Hash: 6e5671dec52db7f64557ba8ef70caf53cf0c782795236b03655623640f9e6a83 -# -# MIT License -# -# Copyright (c) 2024 Jeff Archer -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in all -# copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -from logging import getLogger -from re import DOTALL, compile, findall, search - -from ...config_parser_exception import ConfigParserException -from ..data_utils import bytes_to_int, decode_bytes -from ..dotnet_constants import PATTERN_LDSTR_OP -from ..dotnetpe_payload import DotNetPEPayload -from .config_decryptor import ConfigDecryptor, IncompatibleDecryptorException -from .config_decryptor_plaintext import ConfigDecryptorPlaintext - -logger = getLogger(__name__) - - -class ConfigDecryptorDecryptXOR(ConfigDecryptor): - _KEY_XOR_DECODED_STRINGS = "xor_decoded_strings" - - # Pattern to detect usage of DecryptXOR Method - _PATTERN_DECRYPT_XOR_BLOCK = compile( - rb"(\x2d.\x72.{3}\x70\x28.{3}\x06\x2a(?:\x02[\x16-\x1f].?\x33.\x72.{3}\x70\x28.{3}\x06\x2a){7,}.+?\x72.{3}\x70)", - flags=DOTALL, - ) - - def __init__(self, payload: DotNetPEPayload) -> None: - super().__init__(payload) - # Filled in _get_xor_metadata() - self._xor_strings: list[str] = [] - try: - self._get_xor_metadata() - except Exception as e: - raise IncompatibleDecryptorException(e) - - # Returns a list of decoded XOR-encoded strings found in the payload - def _decode_encoded_strings(self) -> list[str]: - decoded_strings = [] - - for string in self._xor_strings: - decoded = [] - # Do not modify unencoded strings - if ":" not in string: - decoded_strings.append(string) - continue - - # Split encoded string by ':' and run XOR decoding - arr, arr2 = (bytes.fromhex(arr) for arr in string.split(":")) - for idx, byte in enumerate(arr2): - decoded.append(byte ^ self.key[idx % len(self.key)] ^ arr[idx]) - decoded_strings.append(decode_bytes(bytes(decoded))) - - logger.debug(f"Decoded {len(decoded_strings)} strings") - return decoded_strings - - # Parses the config, adds decoded XOR strings, and returns the decoded - # config - def decrypt_encrypted_strings(self, encrypted_strings: dict[str, str]) -> dict[str, list[str] | str]: - config = {} - # Pass off plaintext config to a ConfigDecryptorPlaintext - ptcd = ConfigDecryptorPlaintext(self._payload) - config.update(ptcd.decrypt_encrypted_strings(encrypted_strings)) - config[self._KEY_XOR_DECODED_STRINGS] = self._decode_encoded_strings() - return config - - # Gathers XOR metadata from the payload - def _get_xor_metadata(self): - dxor_block = search(self._PATTERN_DECRYPT_XOR_BLOCK, self._payload.data) - if dxor_block is None: - raise ConfigParserException("Could not identify DecryptXOR block") - logger.debug(f"DecryptXOR block found at offset {hex(dxor_block.start())}") - - # Derive all XOR-encoded string references in the DecryptXOR block - xor_string_rvas = findall(PATTERN_LDSTR_OP, dxor_block.groups()[0]) - self._xor_strings = list( - filter( - None, - [self._payload.user_string_from_rva(bytes_to_int(rva)) for rva in xor_string_rvas], - ) - ) - logger.debug(f"{len(self._xor_strings)} XOR strings found") - - # Get the static constructor containing the XOR key - xor_key_cctor = self._payload.method_from_instruction_offset(dxor_block.start(), step=1, by_token=True) - xor_key_cctor_body = self._payload.method_body_from_method(xor_key_cctor) - - # Derive the XOR key RVA and value - xor_rva = search(PATTERN_LDSTR_OP, xor_key_cctor_body) - if xor_rva is None: - raise ConfigParserException("Could not identify XOR key RVA") - xor_rva = bytes_to_int(xor_rva.groups()[0]) - self.key = bytes(self._payload.user_string_from_rva(xor_rva), encoding="utf-8") - logger.debug(f"XOR key found at {hex(xor_rva)} : {self.key}") diff --git a/lib/parsers_aux/ratking/utils/decryptors/config_decryptor_plaintext.py b/lib/parsers_aux/ratking/utils/decryptors/config_decryptor_plaintext.py deleted file mode 100644 index b24d2b387fd..00000000000 --- a/lib/parsers_aux/ratking/utils/decryptors/config_decryptor_plaintext.py +++ /dev/null @@ -1,124 +0,0 @@ -#!/usr/bin/env python3 -# -# config_decryptor_plaintext.py -# -# Author: jeFF0Falltrades -# -# Provides a fall-through decryptor that will attempt to return the plaintext -# values of a found config when all other decryptors fail by matching known -# config field names from supported RAT families -# -# MIT License -# -# Copyright (c) 2024 Jeff Archer -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in all -# copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -from logging import getLogger - -from ...config_parser_exception import ConfigParserException -from ..dotnetpe_payload import DotNetPEPayload -from .config_decryptor import ConfigDecryptor - -logger = getLogger(__name__) - -KNOWN_CONFIG_FIELD_NAMES = set( - [ - "AUTHKEY", - "An_ti", - "Anti", - "Anti_Process", - "BDOS", - "BS_OD", - "Certifi_cate", - "Certificate", - "DIRECTORY", - "De_lay", - "Delay", - "DoStartup", - "ENABLELOGGER", - "EncryptionKey", - "Groub", - "Group", - "HIDEFILE", - "HIDEINSTALLSUBDIRECTORY", - "HIDELOGDIRECTORY", - "HOSTS", - "Hos_ts", - "Hosts", - "Hw_id", - "Hwid", - "INSTALL", - "INSTALLNAME", - "In_stall", - "Install", - "InstallDir", - "InstallFile", - "InstallFolder", - "InstallStr", - "Install_File", - "Install_Folder", - "Install_path", - "KEY", - "Key", - "LOGDIRECTORYNAME", - "MTX", - "MUTEX", - "Mutex", - "Paste_bin", - "Pastebin", - "Por_ts", - "Port", - "Ports", - "RECONNECTDELAY", - "SPL", - "STARTUP", - "STARTUPKEY", - "SUBDIRECTORY", - "ServerIp", - "ServerPort", - "Server_signa_ture", - "Serversignature", - "Sleep", - "TAG", - "USBNM", - "VERSION", - "Ver_sion", - "Version", - "delay", - "mutex_string", - "startup_name", - ] -) - - -class ConfigDecryptorPlaintext(ConfigDecryptor): - # Minimum threshold for matching Field names - MIN_THRESHOLD_MATCH = 3 - - def __init__(self, payload: DotNetPEPayload) -> None: - super().__init__(payload) - - # Calculates whether the config meets the minimum threshold for known Field - # Names and returns it if it does - def decrypt_encrypted_strings(self, encrypted_strings: dict[str, str]) -> dict[str, str]: - field_names = set(encrypted_strings.keys()) - num_overlapping_field_names = len(KNOWN_CONFIG_FIELD_NAMES & field_names) - if num_overlapping_field_names < self.MIN_THRESHOLD_MATCH: - raise ConfigParserException("Plaintext threshold of known config items not met") - return encrypted_strings diff --git a/lib/parsers_aux/ratking/utils/decryptors/config_decryptor_random_hardcoded.py b/lib/parsers_aux/ratking/utils/decryptors/config_decryptor_random_hardcoded.py deleted file mode 100644 index e5d598f47b7..00000000000 --- a/lib/parsers_aux/ratking/utils/decryptors/config_decryptor_random_hardcoded.py +++ /dev/null @@ -1,96 +0,0 @@ -#!/usr/bin/env python3 -# -# config_decryptor_random_hardcoded.py -# -# Author: jeFF0Falltrades -# -# Provides a custom decryptor for RAT payloads utilizing the method of -# randomly selecting from an embedded list of C2 domains/supradomains -# -# Example hash: a2817702fecb280069f0723cd2d0bfdca63763b9cdc833941c4f33bbe383d93e -# -# MIT License -# -# Copyright (c) 2024 Jeff Archer -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in all -# copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -from logging import getLogger -from re import DOTALL, compile, findall, search - -from ...config_parser_exception import ConfigParserException -from ..data_utils import bytes_to_int -from ..dotnet_constants import PATTERN_LDSTR_OP -from ..dotnetpe_payload import DotNetPEMethod, DotNetPEPayload -from .config_decryptor import ConfigDecryptor, IncompatibleDecryptorException -from .config_decryptor_plaintext import ConfigDecryptorPlaintext - -logger = getLogger(__name__) - - -class ConfigDecryptorRandomHardcoded(ConfigDecryptor): - _KEY_HARDCODED_HOSTS = "hardcoded_hosts" - - # Pattern to find the Method that retrieves a random domain - _PATTERN_RANDOM_DOMAIN = compile(rb"(?:\x73.{3}\x0a){2}\x25.+?\x0a\x06(?:\x6f.{3}\x0a){2}\x0b", flags=DOTALL) - - def __init__(self, payload: DotNetPEPayload) -> None: - super().__init__(payload) - try: - self._random_domain_method = self._get_random_domain_method() - except Exception as e: - raise IncompatibleDecryptorException(e) - - # Returns a combined config containing config fields + hardcoded hosts - def decrypt_encrypted_strings(self, encrypted_strings: dict[str, str]) -> dict[str, list[str] | str]: - config = {} - # Pass off plaintext config to a ConfigDecryptorPlaintext - ptcd = ConfigDecryptorPlaintext(self._payload) - config.update(ptcd.decrypt_encrypted_strings(encrypted_strings)) - config[self._KEY_HARDCODED_HOSTS] = self._get_hardcoded_hosts() - return config - - # Retrieves and returns a list of hardcoded hosts - def _get_hardcoded_hosts(self) -> list[str]: - random_domain_method_body = self._payload.method_body_from_method(self._random_domain_method) - hardcoded_host_rvas = findall(PATTERN_LDSTR_OP, random_domain_method_body) - - hardcoded_hosts = [] - for rva in hardcoded_host_rvas: - try: - harcoded_host = self._payload.user_string_from_rva(bytes_to_int(rva)) - if harcoded_host != ".": - hardcoded_hosts.append(harcoded_host) - except Exception as e: - logger.error(f"Error translating hardcoded host at {hex(rva)}: {e}") - continue - - logger.debug(f"Hardcoded hosts found: {hardcoded_hosts}") - return hardcoded_hosts - - # Retrieves the Method that randomly selects from a list of embedded hosts - def _get_random_domain_method(self) -> DotNetPEMethod: - logger.debug("Searching for random domain method") - random_domain_marker = search(self._PATTERN_RANDOM_DOMAIN, self._payload.data) - if random_domain_marker is None: - raise ConfigParserException("Could not identify random domain generator method") - - random_domain_method = self._payload.method_from_instruction_offset(random_domain_marker.start()) - - logger.debug(f"Random domain generator found at offset {hex(random_domain_method.offset)}") - return random_domain_method diff --git a/lib/parsers_aux/ratking/utils/dotnet_constants.py b/lib/parsers_aux/ratking/utils/dotnet_constants.py deleted file mode 100644 index 84f82e14619..00000000000 --- a/lib/parsers_aux/ratking/utils/dotnet_constants.py +++ /dev/null @@ -1,86 +0,0 @@ -#!/usr/bin/env python3 -# -# dotnet_constants.py -# -# Author: jeFF0Falltrades -# -# Useful .NET constants and enums -# -# MIT License -# -# Copyright (c) 2024 Jeff Archer -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in all -# copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -from enum import IntEnum -from re import DOTALL, compile - -# Notable CIL Opcodes and Tokens -OPCODE_LDC_I4_0 = b"\x16" -OPCODE_LDSTR = b"\x72" -OPCODE_LDTOKEN = b"\xd0" -MDT_FIELD_DEF = 0x04000000 -MDT_METHOD_DEF = 0x06000000 -MDT_STRING = 0x70000000 -PATTERN_LDSTR_OP = compile( - rb"\x72(.{3}\x70)", - flags=DOTALL, -) - - -# IntEnum derivative used for translating a SpecialFolder ID to its name -class SpecialFolder(IntEnum): - ADMINTOOLS = 48 - APPLICATIONDATA = 26 - CDBURNING = 59 - COMMONADMINTOOLS = 47 - COMMONAPPLICATIONDATA = 35 - COMMONDESKTOPDIRECTORY = 25 - COMMONDOCUMENTS = 46 - COMMONMUSIC = 53 - COMMONOEMLINKS = 58 - COMMONPICTURES = 54 - COMMONPROGRAMFILES = 43 - COMMONPROGRAMFILESX86 = 44 - COMMONPROGRAMS = 23 - COMMONSTARTMENU = 22 - COMMONSTARTUP = 24 - COMMONTEMPLATES = 45 - COMMONVIDEOS = 55 - COOKIES = 33 - DESKTOPDIRECTORY = 16 - FONTS = 20 - HISTORY = 34 - INTERNETCACHE = 32 - LOCALAPPLICATIONDATA = 28 - LOCALIZEDRESOURCES = 57 - MYCOMPUTER = 17 - MYMUSIC = 13 - MYPICTURES = 39 - MYVIDEOS = 14 - NETWORKSHORTCUTS = 19 - PRINTERSHORTCUTS = 27 - PROGRAMFILES = 38 - PROGRAMFILESX86 = 42 - RESOURCES = 56 - STARTMENU = 11 - SYSTEM = 37 - SYSTEMX86 = 41 - TEMPLATES = 21 - USERPROFILE = 40 - WINDOWS = 36 diff --git a/lib/parsers_aux/ratking/utils/dotnetpe_payload.py b/lib/parsers_aux/ratking/utils/dotnetpe_payload.py deleted file mode 100644 index d2d9d3f60f3..00000000000 --- a/lib/parsers_aux/ratking/utils/dotnetpe_payload.py +++ /dev/null @@ -1,199 +0,0 @@ -#!/usr/bin/env python3 -# -# dotnetpe_payload.py -# -# Author: jeFF0Falltrades -# -# Provides a wrapper class for accessing metadata from a DotNetPE object and -# performing data conversions -# -# MIT License -# -# Copyright (c) 2024 Jeff Archer -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in all -# copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -from dataclasses import dataclass -from hashlib import sha256 -from logging import getLogger - -from dnfile import dnPE -from yara import Rules - -from ..config_parser_exception import ConfigParserException -from .data_utils import bytes_to_int -from .dotnet_constants import MDT_FIELD_DEF, MDT_METHOD_DEF, MDT_STRING - -logger = getLogger(__name__) - - -# Helper class representing a single Method -@dataclass -class DotNetPEMethod: - name: str - offset: int - rva: int - size: int - token: int - - -class DotNetPEPayload: - # def __init__(self, file_path: str, yara_rule: Rules = None) -> None: - def __init__(self, file_data: bytes, yara_rule: Rules = None) -> None: - # self.file_path = file_path - self.data = file_data # self._get_file_data() - - # Calculate SHA256 - sha256_obj = sha256() - sha256_obj.update(self.data) - self.sha256 = sha256_obj.hexdigest() - - self.dotnetpe: dnPE = None - try: - # self.dotnetpe = dnPE(self.file_path, clr_lazy_load=True) - self.dotnetpe = dnPE(data=file_data, clr_lazy_load=True) - except Exception: - raise ConfigParserException("Failed to load project as dotnet executable") - - self.yara_match = "" - if yara_rule is not None: - self.yara_match = self._match_yara(yara_rule) - - # Pre-sort Method table for efficient lookups - self._methods = self._generate_method_list() - self._methods_by_offset = sorted(self._methods, key=lambda m: m.offset) - self._methods_by_token = sorted(self._methods, key=lambda m: m.token) - - # Given a byte array's size and RVA, translates the RVA to the offset of - # the byte array and returns the bytes of the array as a byte string - def byte_array_from_size_and_rva(self, arr_size: int, arr_rva: int) -> bytes: - arr_field_rva = self.fieldrva_from_rva(arr_rva) - arr_offset = self.offset_from_rva(arr_field_rva) - return self.data[arr_offset : arr_offset + arr_size] - - # Given an offset, and either a terminating offset or delimiter, extracts - # the byte string - def byte_string_from_offset(self, offset_start: int, offstart_end: int = -1, delimiter: bytes = b"\0") -> bytes: - if offstart_end != -1: - try: - return self.data[offset_start:offstart_end] - except Exception: - raise ConfigParserException( - f"Could not extract string value from offset range [{hex(offset_start)}:{offstart_end}]" - ) - try: - return self.data[offset_start:].partition(delimiter)[0] - except Exception: - raise ConfigParserException( - f"Could not extract string value from offset {hex(offset_start)} with delimiter {delimiter}" - ) - - # Given an RVA, derives the corresponding Field name - def field_name_from_rva(self, rva: int) -> str: - try: - return self.dotnetpe.net.mdtables.Field.rows[(rva ^ MDT_FIELD_DEF) - 1].Name.value - except Exception: - raise ConfigParserException(f"Could not find Field for RVA {rva}") - - # Given an RVA, derives the corresponding FieldRVA value - def fieldrva_from_rva(self, rva: int) -> int: - field_id = rva ^ MDT_FIELD_DEF - for row in self.dotnetpe.net.mdtables.FieldRva: - if row.struct.Field_Index == field_id: - return row.struct.Rva - raise ConfigParserException(f"Could not find FieldRVA for RVA {rva}") - - # Generates a list of DotNetPEMethod objects for efficient lookups of method - # metadata in other operations - def _generate_method_list( - self, - ) -> list[DotNetPEMethod]: - method_objs = [] - - for idx, method in enumerate(self.dotnetpe.net.mdtables.MethodDef.rows): - method_offset = self.offset_from_rva(method.Rva) - - # Parse size from flags - flags = self.data[method_offset] - method_size = 0 - if flags & 3 == 2: # Tiny format - method_size = flags >> 2 - elif flags & 3 == 3: # Fat format (add 12-byte header) - method_size = 12 + bytes_to_int(self.data[method_offset + 4 : method_offset + 8]) - - method_objs.append( - DotNetPEMethod( - method.Name.value, - method_offset, - method.Rva, - method_size, - (MDT_METHOD_DEF ^ idx) + 1, - ) - ) - return method_objs - - # Returns payload binary content - def _get_file_data(self) -> bytes: - logger.debug(f"Reading contents from: {self.file_path}") - try: - with open(self.file_path, "rb") as fp: - data = fp.read() - except Exception: - raise ConfigParserException(f"Error reading from path: {self.file_path}") - logger.debug(f"Successfully read {len(data)} bytes") - return data - - # Tests a given YARA rule object against the file at self.file_path, - # returning the matching rule's name, or "No match" - def _match_yara(self, rule: Rules) -> str: - try: - match = rule.match(self.file_path) - return str(match[0]) if len(match) > 0 else "No match" - except Exception as e: - logger.exception(e) - return f"Exception encountered: {e}" - - # Given a DotNetPEMethod, returns its body as raw bytes - def method_body_from_method(self, method: DotNetPEMethod) -> bytes: - return self.byte_string_from_offset(method.offset, method.offset + method.size) - - # Given a Method name, returns a list of DotNetPEMethods matching that name - def methods_from_name(self, name: str) -> list[DotNetPEMethod]: - return [method for method in self._methods if method.name == name] - - # Given the offset to an instruction, reverses the instruction to its - # parent Method, optionally returning an adjacent Method using step to - # signify the direction of adjacency, and using by_token to determine - # whether to calculate adjacency by token or offset - def method_from_instruction_offset(self, ins_offset: int, step: int = 0, by_token: bool = False) -> DotNetPEMethod: - for idx, method in enumerate(self._methods_by_offset): - if method.offset <= ins_offset < method.offset + method.size: - return ( - self._methods_by_token[self._methods_by_token.index(method) + step] - if by_token - else self._methods_by_offset[idx + step] - ) - raise ConfigParserException(f"Could not find method from instruction offset {hex(ins_offset)}") - - # Given an RVA, returns a data/file offset - def offset_from_rva(self, rva: int) -> int: - return self.dotnetpe.get_offset_from_rva(rva) - - # Given an RVA, derives the corresponding User String - def user_string_from_rva(self, rva: int) -> str: - return self.dotnetpe.net.user_strings.get(rva ^ MDT_STRING).value diff --git a/modules/processing/parsers/CAPE/AsyncRAT.py b/modules/processing/parsers/CAPE/AsyncRAT.py index 29c59a04fa2..1220071ea7d 100644 --- a/modules/processing/parsers/CAPE/AsyncRAT.py +++ b/modules/processing/parsers/CAPE/AsyncRAT.py @@ -1,4 +1,4 @@ -from lib.parsers_aux.ratking import RATConfigParser +from rat_king_parser.rkp import RATConfigParser def extract_config(data: bytes): diff --git a/modules/processing/parsers/CAPE/DCRat.py b/modules/processing/parsers/CAPE/DCRat.py index 29c59a04fa2..1220071ea7d 100644 --- a/modules/processing/parsers/CAPE/DCRat.py +++ b/modules/processing/parsers/CAPE/DCRat.py @@ -1,4 +1,4 @@ -from lib.parsers_aux.ratking import RATConfigParser +from rat_king_parser.rkp import RATConfigParser def extract_config(data: bytes): diff --git a/modules/processing/parsers/CAPE/QuasarRAT.py b/modules/processing/parsers/CAPE/QuasarRAT.py index 29c59a04fa2..1220071ea7d 100644 --- a/modules/processing/parsers/CAPE/QuasarRAT.py +++ b/modules/processing/parsers/CAPE/QuasarRAT.py @@ -1,4 +1,4 @@ -from lib.parsers_aux.ratking import RATConfigParser +from rat_king_parser.rkp import RATConfigParser def extract_config(data: bytes): diff --git a/modules/processing/parsers/CAPE/VenomRAT.py b/modules/processing/parsers/CAPE/VenomRAT.py index 29c59a04fa2..1220071ea7d 100644 --- a/modules/processing/parsers/CAPE/VenomRAT.py +++ b/modules/processing/parsers/CAPE/VenomRAT.py @@ -1,4 +1,4 @@ -from lib.parsers_aux.ratking import RATConfigParser +from rat_king_parser.rkp import RATConfigParser def extract_config(data: bytes): diff --git a/modules/processing/parsers/CAPE/XWorm.py b/modules/processing/parsers/CAPE/XWorm.py index 29c59a04fa2..1220071ea7d 100644 --- a/modules/processing/parsers/CAPE/XWorm.py +++ b/modules/processing/parsers/CAPE/XWorm.py @@ -1,4 +1,4 @@ -from lib.parsers_aux.ratking import RATConfigParser +from rat_king_parser.rkp import RATConfigParser def extract_config(data: bytes): diff --git a/modules/processing/parsers/CAPE/XenoRAT.py b/modules/processing/parsers/CAPE/XenoRAT.py index 29c59a04fa2..1220071ea7d 100644 --- a/modules/processing/parsers/CAPE/XenoRAT.py +++ b/modules/processing/parsers/CAPE/XenoRAT.py @@ -1,4 +1,4 @@ -from lib.parsers_aux.ratking import RATConfigParser +from rat_king_parser.rkp import RATConfigParser def extract_config(data: bytes): diff --git a/poetry.lock b/poetry.lock index 9aeb10ad277..26063d23dd1 100644 --- a/poetry.lock +++ b/poetry.lock @@ -3303,6 +3303,29 @@ files = [ [package.dependencies] pycryptodomex = "*" +[[package]] +name = "rat-king-parser" +version = "3.0.0" +description = "A robust, multiprocessing-capable, multi-family RAT config parser/config extractor for AsyncRAT, DcRAT, VenomRAT, QuasarRAT, XWorm, Xeno RAT, and cloned/derivative RAT families." +optional = false +python-versions = ">=3.10" +files = [] +develop = false + +[package.dependencies] +cryptography = "*" +dnfile = "*" +yara-python = "*" + +[package.extras] +maco = ["maco", "validators"] + +[package.source] +type = "git" +url = "https://github.com/jeFF0Falltrades/rat_king_parser" +reference = "ab849ec8face38c8dac3f803ae5fe7cf8be26583" +resolved_reference = "ab849ec8face38c8dac3f803ae5fe7cf8be26583" + [[package]] name = "regex" version = "2021.7.6" @@ -4615,4 +4638,4 @@ maco = ["maco"] [metadata] lock-version = "2.0" python-versions = ">=3.10, <4.0" -content-hash = "ab3f807dcdc7fa1fb2098ee2222602ffde65894297ca6b4c3629f2528d584d09" +content-hash = "ab65373ef8c8244e2d8237cb6208783a0276fa62f52545098cb12170c1cd7d76" diff --git a/pyproject.toml b/pyproject.toml index 43be4a45a58..2d50b19820a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -91,6 +91,8 @@ setproctitle = "1.3.2" # tmp dependency to fix vuln certifi = "2024.7.4" +rat_king_parser = {git = "https://github.com/jeFF0Falltrades/rat_king_parser", rev = "ab849ec8face38c8dac3f803ae5fe7cf8be26583"} + [tool.poetry.extras] maco = ["maco"] From ff0af74edb813d77ae384f7fae4d0631f882ed37 Mon Sep 17 00:00:00 2001 From: GitHub Actions Date: Wed, 30 Oct 2024 15:32:19 +0000 Subject: [PATCH 025/121] ci: Update requirements.txt --- requirements.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/requirements.txt b/requirements.txt index 41e5505d9a5..4b920a5528a 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1448,6 +1448,7 @@ pyyaml==6.0.2 ; python_version >= "3.10" and python_version < "4.0" \ pyzipper==0.3.5 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:6040069654dad040cf8708d4db78ce5829238e2091ad8006a47d97d6ffe275d6 \ --hash=sha256:e696e9d306427400e23e13a766c7614b64d9fc3316bdc71bbcc8f0070a14f150 +rat-king-parser @ git+https://github.com/jeFF0Falltrades/rat_king_parser@ab849ec8face38c8dac3f803ae5fe7cf8be26583 ; python_version >= "3.10" and python_version < "4.0" regex==2021.7.6 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:0eb2c6e0fcec5e0f1d3bcc1133556563222a2ffd2211945d7b1480c1b1a42a6f \ --hash=sha256:15dddb19823f5147e7517bb12635b3c82e6f2a3a6b696cc3e321522e8b9308ad \ From 09c7d13ed37e60ba5194598388410931833bbcf4 Mon Sep 17 00:00:00 2001 From: doomedraven Date: Thu, 31 Oct 2024 12:47:12 +0100 Subject: [PATCH 026/121] add poetry-plugin-export --- .github/actions/python-setup/action.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/actions/python-setup/action.yml b/.github/actions/python-setup/action.yml index 4608efbbd9c..d547756a877 100644 --- a/.github/actions/python-setup/action.yml +++ b/.github/actions/python-setup/action.yml @@ -16,7 +16,7 @@ runs: - name: Install poetry shell: bash - run: PIP_BREAK_SYSTEM_PACKAGES=1 pip install poetry + run: PIP_BREAK_SYSTEM_PACKAGES=1 pip install poetry poetry-plugin-export - name: Set up Python ${{ inputs.python-version }} uses: actions/setup-python@v5 From 0eb355348a4c596e1f25328bdaf3faf4eefd5540 Mon Sep 17 00:00:00 2001 From: ClaudioWayne <35531629+ClaudioWayne@users.noreply.github.com> Date: Thu, 31 Oct 2024 14:00:24 +0100 Subject: [PATCH 027/121] toggle advanced options and tooltips (#2384) * button to toggle the visibility of the "Advanced Options" section * Add tooltips to advanced options --- web/templates/submission/index.html | 183 +++++++++++++++------------- 1 file changed, 96 insertions(+), 87 deletions(-) diff --git a/web/templates/submission/index.html b/web/templates/submission/index.html index 0efd0579f21..91947c0aee2 100644 --- a/web/templates/submission/index.html +++ b/web/templates/submission/index.html @@ -60,6 +60,8 @@ let title = $('option:selected', this).attr('title'); $("#package_description").text(title); }); + // tooltips + $('[data-toggle="tooltip"]').tooltip(); });
@@ -606,93 +608,100 @@
-
- -
- {% if config.procmemory %} -
- -
- {% endif %} - {% if config.amsidump %} -
- -
- {% endif %} -
- -
- {% if config.memory %} -
- -
- {% endif %} -
- -
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
- {% if config.kernel %} -
- -
- {% endif %} -
- -
-
- + + + +
+
+ +
+ {% if config.procmemory %} +
+ +
+ {% endif %} + {% if config.amsidump %} +
+ +
+ {% endif %} +
+ +
+ {% if config.memory %} +
+ +
+ {% endif %} +
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+ {% if config.kernel %} +
+ +
+ {% endif %} +
+ +
+
+ +
From 9c25c80ec0533beb8088e8df896f8e9b2e1927e1 Mon Sep 17 00:00:00 2001 From: YungBinary <93540406+YungBinary@users.noreply.github.com> Date: Thu, 31 Oct 2024 14:21:53 -0600 Subject: [PATCH 028/121] Fix/improve parsers (#2385) --- modules/processing/parsers/CAPE/Lumma.py | 10 +++------ modules/processing/parsers/CAPE/Stealc.py | 25 +++++++++++------------ 2 files changed, 15 insertions(+), 20 deletions(-) diff --git a/modules/processing/parsers/CAPE/Lumma.py b/modules/processing/parsers/CAPE/Lumma.py index 05a50025994..62819eb6011 100644 --- a/modules/processing/parsers/CAPE/Lumma.py +++ b/modules/processing/parsers/CAPE/Lumma.py @@ -1,6 +1,5 @@ import base64 import re - import pefile @@ -41,11 +40,8 @@ def get_rdata(data): def xor_data(data, key): decoded = bytearray() - key_len = len(key) for i in range(len(data)): - if i >= key_len: - break - decoded.append(data[i] ^ key[i]) + decoded.append(data[i] ^ key[i % len(data)]) return decoded @@ -82,8 +78,8 @@ def extract_config(data): for base64_str in base64_strings: try: decoded_bytes = base64.b64decode(base64_str, validate=True) - encoded_c2 = decoded_bytes[:32] - xor_key = decoded_bytes[32:] + encoded_c2 = decoded_bytes[32:] + xor_key = decoded_bytes[:32] decoded_c2 = xor_data(encoded_c2, xor_key) if not contains_non_printable(decoded_c2): diff --git a/modules/processing/parsers/CAPE/Stealc.py b/modules/processing/parsers/CAPE/Stealc.py index 0d2f5a35025..1e11fd1c597 100644 --- a/modules/processing/parsers/CAPE/Stealc.py +++ b/modules/processing/parsers/CAPE/Stealc.py @@ -4,8 +4,6 @@ import pefile import yara -MAX_STRING_SIZE = 100 - # Hash = 619751f5ed0a9716318092998f2e4561f27f7f429fe6103406ecf16e33837470 RULE_SOURCE = """rule StealC @@ -45,10 +43,6 @@ def xor_data(data, key): return decoded -def string_from_offset(data, offset): - return data[offset : offset + MAX_STRING_SIZE].split(b"\0", 1)[0] - - def extract_config(data): config_dict = {} @@ -73,7 +67,8 @@ def extract_config(data): # config_dict["Strings"] = [] pe = pefile.PE(data=data, fast_load=False) image_base = pe.OPTIONAL_HEADER.ImageBase - + domain = "" + uri = "" for str_decode_offset in yara_scan(data): str_size = int(data[str_decode_offset + 1]) # Ignore size 0 strings @@ -88,15 +83,19 @@ def extract_config(data): encoded_str_offset = pe.get_offset_from_rva(struct.unpack("i", encoded_str_rva)[0] - image_base) # dword_offset = hex(struct.unpack("i", dword_rva)[0])[2:] - key = string_from_offset(data, key_offset) - encoded_str = string_from_offset(data, encoded_str_offset) - + key = data[key_offset : key_offset + str_size] + encoded_str = data[encoded_str_offset : encoded_str_offset + str_size] decoded_str = xor_data(encoded_str, key).decode() - if ("http://" in decoded_str or "https://" in decoded_str) and len(decoded_str) > 11: - config_dict.setdefault("C2", []).append(decoded_str) - # else: + if decoded_str.startswith("http") and "://" in decoded_str: + domain = decoded_str + elif decoded_str.startswith("/") and decoded_str[-4] == ".": + uri = decoded_str + #else: # config_dict["Strings"].append({f"dword_{dword_offset}" : decoded_str}) + if domain and uri: + config_dict.setdefault("C2", []).append(f"{domain}{uri}") + return config_dict From a443fbc2a5049b08cc7ee6faf356aceb12b63ecf Mon Sep 17 00:00:00 2001 From: GitHub Actions Date: Thu, 31 Oct 2024 20:23:02 +0000 Subject: [PATCH 029/121] style: Automatic code formatting --- modules/processing/parsers/CAPE/Lumma.py | 1 + modules/processing/parsers/CAPE/Stealc.py | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/modules/processing/parsers/CAPE/Lumma.py b/modules/processing/parsers/CAPE/Lumma.py index 62819eb6011..85a84c6839a 100644 --- a/modules/processing/parsers/CAPE/Lumma.py +++ b/modules/processing/parsers/CAPE/Lumma.py @@ -1,5 +1,6 @@ import base64 import re + import pefile diff --git a/modules/processing/parsers/CAPE/Stealc.py b/modules/processing/parsers/CAPE/Stealc.py index 1e11fd1c597..b9259f3d9ac 100644 --- a/modules/processing/parsers/CAPE/Stealc.py +++ b/modules/processing/parsers/CAPE/Stealc.py @@ -90,7 +90,7 @@ def extract_config(data): domain = decoded_str elif decoded_str.startswith("/") and decoded_str[-4] == ".": uri = decoded_str - #else: + # else: # config_dict["Strings"].append({f"dword_{dword_offset}" : decoded_str}) if domain and uri: From bdbc19d3772be247717bce01b6f5581b5e0da2d6 Mon Sep 17 00:00:00 2001 From: YungBinary <93540406+YungBinary@users.noreply.github.com> Date: Thu, 31 Oct 2024 17:01:16 -0600 Subject: [PATCH 030/121] Update stealc test (#2386) --- tests_parsers/test_stealc.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests_parsers/test_stealc.py b/tests_parsers/test_stealc.py index 79b238dd3e8..12a98def5df 100644 --- a/tests_parsers/test_stealc.py +++ b/tests_parsers/test_stealc.py @@ -9,5 +9,5 @@ def test_stealc(): with open("tests/data/malware/619751f5ed0a9716318092998f2e4561f27f7f429fe6103406ecf16e33837470", "rb") as data: conf = extract_config(data.read()) assert conf == { - "C2": ["http://95.217.125.57"], + "C2": ["http://95.217.125.57/2f571d994666c8cb.php"], } From fd4b9311f665ea799cca3133e643507095f8f9f3 Mon Sep 17 00:00:00 2001 From: doomedraven Date: Fri, 1 Nov 2024 22:08:45 +0100 Subject: [PATCH 031/121] parsers_split (#2383) * parsers_split --- .github/workflows/python-package-windows.yml | 2 +- .github/workflows/python-package.yml | 14 +- changelog.md | 8 + lib/cuckoo/common/aplib.py | 162 -- lib/cuckoo/common/blzpack.py | 89 - lib/cuckoo/common/blzpack_lib.so | Bin 33368 -> 0 bytes lib/cuckoo/common/cape_utils.py | 67 +- lib/cuckoo/common/integrations/lznt1.py | 132 -- modules/processing/parsers/CAPE/AgentTesla.py | 74 - modules/processing/parsers/CAPE/AsyncRAT.py | 5 - .../processing/parsers/CAPE/AuroraStealer.py | 73 - modules/processing/parsers/CAPE/Azorult.py | 80 - .../processing/parsers/CAPE/BackOffLoader.py | 44 - modules/processing/parsers/CAPE/BackOffPOS.py | 45 - modules/processing/parsers/CAPE/BitPaymer.py | 91 - .../processing/parsers/CAPE/BlackDropper.py | 96 - modules/processing/parsers/CAPE/BlackNix.py | 57 - modules/processing/parsers/CAPE/Blister.py | 557 ----- modules/processing/parsers/CAPE/BruteRatel.py | 28 - modules/processing/parsers/CAPE/BuerLoader.py | 39 - modules/processing/parsers/CAPE/BumbleBee.py | 242 -- modules/processing/parsers/CAPE/Carbanak.py | 186 -- modules/processing/parsers/CAPE/ChChes.py | 75 - .../parsers/CAPE/CobaltStrikeBeacon.py | 463 ---- .../parsers/CAPE/CobaltStrikeStager.py | 190 -- modules/processing/parsers/CAPE/DCRat.py | 5 - modules/processing/parsers/CAPE/DarkGate.py | 118 - .../processing/parsers/CAPE/DoppelPaymer.py | 78 - .../processing/parsers/CAPE/DridexLoader.py | 175 -- modules/processing/parsers/CAPE/Emotet.py | 832 ------- modules/processing/parsers/CAPE/Enfal.py | 106 - modules/processing/parsers/CAPE/EvilGrab.py | 110 - modules/processing/parsers/CAPE/Fareit.py | 69 - modules/processing/parsers/CAPE/Formbook.py | 22 - modules/processing/parsers/CAPE/Greame.py | 90 - modules/processing/parsers/CAPE/GuLoader.py | 17 - modules/processing/parsers/CAPE/Hancitor.py | 78 - .../processing/parsers/CAPE/HttpBrowser.py | 124 - modules/processing/parsers/CAPE/IcedID.py | 81 - .../processing/parsers/CAPE/IcedIDLoader.py | 48 - modules/processing/parsers/CAPE/KoiLoader.py | 130 - .../processing/parsers/CAPE/Latrodectus.py | 199 -- modules/processing/parsers/CAPE/LokiBot.py | 168 -- modules/processing/parsers/CAPE/Lumma.py | 100 - modules/processing/parsers/CAPE/NanoCore.py | 200 -- modules/processing/parsers/CAPE/Nighthawk.py | 356 --- modules/processing/parsers/CAPE/Njrat.py | 193 -- modules/processing/parsers/CAPE/Oyster.py | 126 - modules/processing/parsers/CAPE/Pandora.py | 77 - .../parsers/CAPE/PhemedroneStealer.py | 191 -- modules/processing/parsers/CAPE/PikaBot.py | 186 -- modules/processing/parsers/CAPE/PlugX.py | 325 --- modules/processing/parsers/CAPE/PoisonIvy.py | 128 - modules/processing/parsers/CAPE/Punisher.py | 35 - modules/processing/parsers/CAPE/QakBot.py | 503 ---- modules/processing/parsers/CAPE/QuasarRAT.py | 5 - modules/processing/parsers/CAPE/Quickbind.py | 87 - modules/processing/parsers/CAPE/RCSession.py | 121 - modules/processing/parsers/CAPE/REvil.py | 85 - modules/processing/parsers/CAPE/RedLeaf.py | 109 - modules/processing/parsers/CAPE/RedLine.py | 182 -- modules/processing/parsers/CAPE/Remcos.py | 207 -- modules/processing/parsers/CAPE/Retefe.py | 146 -- .../processing/parsers/CAPE/Rhadamanthys.py | 9 - modules/processing/parsers/CAPE/Rozena.py | 16 - modules/processing/parsers/CAPE/SmallNet.py | 103 - .../processing/parsers/CAPE/SmokeLoader.py | 90 - .../processing/parsers/CAPE/Socks5Systemz.py | 25 - modules/processing/parsers/CAPE/SparkRAT.py | 73 - .../processing/parsers/CAPE/SquirrelWaffle.py | 87 - modules/processing/parsers/CAPE/Stealc.py | 106 - modules/processing/parsers/CAPE/Strrat.py | 80 - modules/processing/parsers/CAPE/TSCookie.py | 170 -- modules/processing/parsers/CAPE/TrickBot.py | 198 -- modules/processing/parsers/CAPE/UrsnifV3.py | 158 -- modules/processing/parsers/CAPE/VenomRAT.py | 5 - modules/processing/parsers/CAPE/WarzoneRAT.py | 122 - modules/processing/parsers/CAPE/XWorm.py | 5 - modules/processing/parsers/CAPE/XenoRAT.py | 5 - modules/processing/parsers/CAPE/Zloader.py | 139 -- modules/processing/parsers/CAPE/__init__.py | 1 - .../parsers/CAPE/deprecated/JavaDropper.py | 105 - .../parsers/CAPE/deprecated/Nymaim.py | 264 --- .../parsers/CAPE/deprecated/PredatorPain.py | 178 -- .../parsers/CAPE/deprecated/_ShadowTech.py | 117 - .../parsers/CAPE/deprecated/_VirusRat.py | 69 - .../parsers/CAPE/deprecated/_jRat.py | 196 -- .../parsers/CAPE/deprecated/unrecom.py | 64 - .../parsers/CAPE/deprecated/xRAT.py | 114 - modules/processing/parsers/CAPE/test_cape.py | 2 - modules/processing/parsers/MACO/AgentTesla.py | 64 - modules/processing/parsers/MACO/AsyncRAT.py | 51 - .../processing/parsers/MACO/AuroraStealer.py | 29 - modules/processing/parsers/MACO/Azorult.py | 22 - .../processing/parsers/MACO/BackOffLoader.py | 33 - modules/processing/parsers/MACO/BackOffPOS.py | 33 - modules/processing/parsers/MACO/BitPaymer.py | 29 - .../processing/parsers/MACO/BlackDropper.py | 32 - modules/processing/parsers/MACO/BlackNix.py | 66 - modules/processing/parsers/MACO/Blister.py | 36 - modules/processing/parsers/MACO/BruteRatel.py | 32 - modules/processing/parsers/MACO/BuerLoader.py | 28 - modules/processing/parsers/MACO/BumbleBee.py | 46 - modules/processing/parsers/MACO/Carbanak.py | 45 - modules/processing/parsers/MACO/ChChes.py | 28 - .../parsers/MACO/CobaltStrikeBeacon.py | 50 - .../parsers/MACO/CobaltStrikeStager.py | 26 - modules/processing/parsers/MACO/DCRat.py | 27 - modules/processing/parsers/MACO/DarkGate.py | 52 - .../processing/parsers/MACO/DoppelPaymer.py | 30 - .../processing/parsers/MACO/DridexLoader.py | 33 - modules/processing/parsers/MACO/Emotet.py | 32 - modules/processing/parsers/MACO/Enfal.py | 25 - modules/processing/parsers/MACO/EvilGrab.py | 38 - modules/processing/parsers/MACO/Fareit.py | 27 - modules/processing/parsers/MACO/Formbook.py | 32 - modules/processing/parsers/MACO/Greame.py | 23 - modules/processing/parsers/MACO/GuLoader.py | 29 - modules/processing/parsers/MACO/Hancitor.py | 32 - .../processing/parsers/MACO/HttpBrowser.py | 35 - modules/processing/parsers/MACO/IcedID.py | 24 - .../processing/parsers/MACO/IcedIDLoader.py | 32 - modules/processing/parsers/MACO/KoiLoader.py | 27 - .../processing/parsers/MACO/Latrodectus.py | 44 - modules/processing/parsers/MACO/LokiBot.py | 29 - modules/processing/parsers/MACO/Lumma.py | 29 - modules/processing/parsers/MACO/NanoCore.py | 44 - modules/processing/parsers/MACO/Nighthawk.py | 26 - modules/processing/parsers/MACO/Njrat.py | 33 - modules/processing/parsers/MACO/Oyster.py | 35 - modules/processing/parsers/MACO/Pandora.py | 50 - .../parsers/MACO/PhemedroneStealer.py | 23 - modules/processing/parsers/MACO/PikaBot.py | 35 - modules/processing/parsers/MACO/PlugX.py | 23 - modules/processing/parsers/MACO/PoisonIvy.py | 45 - modules/processing/parsers/MACO/Punisher.py | 46 - modules/processing/parsers/MACO/QakBot.py | 28 - modules/processing/parsers/MACO/QuasarRAT.py | 26 - modules/processing/parsers/MACO/Quickbind.py | 35 - modules/processing/parsers/MACO/RCSession.py | 44 - modules/processing/parsers/MACO/REvil.py | 23 - modules/processing/parsers/MACO/RedLeaf.py | 36 - modules/processing/parsers/MACO/RedLine.py | 27 - modules/processing/parsers/MACO/Remcos.py | 26 - modules/processing/parsers/MACO/Retefe.py | 24 - .../processing/parsers/MACO/Rhadamanthys.py | 27 - modules/processing/parsers/MACO/Rozena.py | 27 - modules/processing/parsers/MACO/SmallNet.py | 26 - .../processing/parsers/MACO/SmokeLoader.py | 26 - .../processing/parsers/MACO/Socks5Systemz.py | 31 - modules/processing/parsers/MACO/SparkRAT.py | 34 - .../processing/parsers/MACO/SquirrelWaffle.py | 26 - modules/processing/parsers/MACO/Stealc.py | 26 - modules/processing/parsers/MACO/Strrat.py | 23 - modules/processing/parsers/MACO/TSCookie.py | 26 - modules/processing/parsers/MACO/TrickBot.py | 24 - modules/processing/parsers/MACO/UrsnifV3.py | 26 - modules/processing/parsers/MACO/VenomRat.py | 23 - modules/processing/parsers/MACO/WarzoneRAT.py | 27 - modules/processing/parsers/MACO/XWorm.py | 26 - modules/processing/parsers/MACO/XenoRAT.py | 26 - modules/processing/parsers/MACO/Zloader.py | 33 - modules/processing/parsers/MACO/__init__.py | 1 - modules/processing/parsers/MACO/test_maco.py | 10 - .../parsers/RATDecoders/__init__.py | 1 - .../parsers/RATDecoders/test_rats.py | 13 - modules/processing/parsers/__init__.py | 1 - modules/processing/parsers/malduck/LICENSE | 674 ------ modules/processing/parsers/malduck/README.md | 29 - .../processing/parsers/malduck/__init__.py | 0 .../parsers/malduck/test_malduck.py | 15 - .../processing/parsers/mwcp/SmokeLoader.py | 165 -- modules/processing/parsers/mwcp/__init__.py | 0 modules/processing/parsers/mwcp/test_mwcp.py | 9 - poetry.lock | 2104 +++++++---------- pyproject.toml | 15 +- tests/test_aplib.py | 10 - tests_parsers/readme.md | 2 - tests_parsers/test_agenttesla.py | 49 - tests_parsers/test_asyncrat.py | 44 - tests_parsers/test_aurorastealer.py | 38 - tests_parsers/test_blackdropper.py | 36 - tests_parsers/test_bumblebee.py | 28 - tests_parsers/test_carbanak.py | 21 - tests_parsers/test_cobaltstrikebeacon.py | 125 - tests_parsers/test_darkgate.py | 21 - tests_parsers/test_icedid.py | 22 - tests_parsers/test_koiloader.py | 28 - tests_parsers/test_latrodectus.py | 293 --- tests_parsers/test_lumma.py | 59 - tests_parsers/test_nanocore.py | 108 - tests_parsers/test_njrat.py | 63 - tests_parsers/test_oyster.py | 35 - tests_parsers/test_pikabot.py | 120 - tests_parsers/test_qakbot.py | 10 - tests_parsers/test_quickbind.py | 35 - tests_parsers/test_redline.py | 35 - tests_parsers/test_smokeloader.py | 24 - tests_parsers/test_snake.py | 14 - tests_parsers/test_sparkrat.py | 36 - tests_parsers/test_stealc.py | 13 - tests_parsers/test_zloader.py | 36 - 202 files changed, 854 insertions(+), 16956 deletions(-) delete mode 100644 lib/cuckoo/common/aplib.py delete mode 100644 lib/cuckoo/common/blzpack.py delete mode 100755 lib/cuckoo/common/blzpack_lib.so delete mode 100644 lib/cuckoo/common/integrations/lznt1.py delete mode 100644 modules/processing/parsers/CAPE/AgentTesla.py delete mode 100644 modules/processing/parsers/CAPE/AsyncRAT.py delete mode 100644 modules/processing/parsers/CAPE/AuroraStealer.py delete mode 100644 modules/processing/parsers/CAPE/Azorult.py delete mode 100644 modules/processing/parsers/CAPE/BackOffLoader.py delete mode 100644 modules/processing/parsers/CAPE/BackOffPOS.py delete mode 100644 modules/processing/parsers/CAPE/BitPaymer.py delete mode 100644 modules/processing/parsers/CAPE/BlackDropper.py delete mode 100644 modules/processing/parsers/CAPE/BlackNix.py delete mode 100644 modules/processing/parsers/CAPE/Blister.py delete mode 100644 modules/processing/parsers/CAPE/BruteRatel.py delete mode 100644 modules/processing/parsers/CAPE/BuerLoader.py delete mode 100644 modules/processing/parsers/CAPE/BumbleBee.py delete mode 100644 modules/processing/parsers/CAPE/Carbanak.py delete mode 100644 modules/processing/parsers/CAPE/ChChes.py delete mode 100644 modules/processing/parsers/CAPE/CobaltStrikeBeacon.py delete mode 100644 modules/processing/parsers/CAPE/CobaltStrikeStager.py delete mode 100644 modules/processing/parsers/CAPE/DCRat.py delete mode 100644 modules/processing/parsers/CAPE/DarkGate.py delete mode 100644 modules/processing/parsers/CAPE/DoppelPaymer.py delete mode 100644 modules/processing/parsers/CAPE/DridexLoader.py delete mode 100644 modules/processing/parsers/CAPE/Emotet.py delete mode 100644 modules/processing/parsers/CAPE/Enfal.py delete mode 100644 modules/processing/parsers/CAPE/EvilGrab.py delete mode 100644 modules/processing/parsers/CAPE/Fareit.py delete mode 100644 modules/processing/parsers/CAPE/Formbook.py delete mode 100644 modules/processing/parsers/CAPE/Greame.py delete mode 100644 modules/processing/parsers/CAPE/GuLoader.py delete mode 100644 modules/processing/parsers/CAPE/Hancitor.py delete mode 100644 modules/processing/parsers/CAPE/HttpBrowser.py delete mode 100644 modules/processing/parsers/CAPE/IcedID.py delete mode 100644 modules/processing/parsers/CAPE/IcedIDLoader.py delete mode 100644 modules/processing/parsers/CAPE/KoiLoader.py delete mode 100644 modules/processing/parsers/CAPE/Latrodectus.py delete mode 100644 modules/processing/parsers/CAPE/LokiBot.py delete mode 100644 modules/processing/parsers/CAPE/Lumma.py delete mode 100644 modules/processing/parsers/CAPE/NanoCore.py delete mode 100644 modules/processing/parsers/CAPE/Nighthawk.py delete mode 100644 modules/processing/parsers/CAPE/Njrat.py delete mode 100644 modules/processing/parsers/CAPE/Oyster.py delete mode 100644 modules/processing/parsers/CAPE/Pandora.py delete mode 100644 modules/processing/parsers/CAPE/PhemedroneStealer.py delete mode 100644 modules/processing/parsers/CAPE/PikaBot.py delete mode 100644 modules/processing/parsers/CAPE/PlugX.py delete mode 100644 modules/processing/parsers/CAPE/PoisonIvy.py delete mode 100644 modules/processing/parsers/CAPE/Punisher.py delete mode 100644 modules/processing/parsers/CAPE/QakBot.py delete mode 100644 modules/processing/parsers/CAPE/QuasarRAT.py delete mode 100644 modules/processing/parsers/CAPE/Quickbind.py delete mode 100644 modules/processing/parsers/CAPE/RCSession.py delete mode 100644 modules/processing/parsers/CAPE/REvil.py delete mode 100644 modules/processing/parsers/CAPE/RedLeaf.py delete mode 100644 modules/processing/parsers/CAPE/RedLine.py delete mode 100644 modules/processing/parsers/CAPE/Remcos.py delete mode 100644 modules/processing/parsers/CAPE/Retefe.py delete mode 100644 modules/processing/parsers/CAPE/Rhadamanthys.py delete mode 100644 modules/processing/parsers/CAPE/Rozena.py delete mode 100644 modules/processing/parsers/CAPE/SmallNet.py delete mode 100644 modules/processing/parsers/CAPE/SmokeLoader.py delete mode 100644 modules/processing/parsers/CAPE/Socks5Systemz.py delete mode 100644 modules/processing/parsers/CAPE/SparkRAT.py delete mode 100644 modules/processing/parsers/CAPE/SquirrelWaffle.py delete mode 100644 modules/processing/parsers/CAPE/Stealc.py delete mode 100644 modules/processing/parsers/CAPE/Strrat.py delete mode 100644 modules/processing/parsers/CAPE/TSCookie.py delete mode 100644 modules/processing/parsers/CAPE/TrickBot.py delete mode 100644 modules/processing/parsers/CAPE/UrsnifV3.py delete mode 100644 modules/processing/parsers/CAPE/VenomRAT.py delete mode 100644 modules/processing/parsers/CAPE/WarzoneRAT.py delete mode 100644 modules/processing/parsers/CAPE/XWorm.py delete mode 100644 modules/processing/parsers/CAPE/XenoRAT.py delete mode 100644 modules/processing/parsers/CAPE/Zloader.py delete mode 100644 modules/processing/parsers/CAPE/__init__.py delete mode 100644 modules/processing/parsers/CAPE/deprecated/JavaDropper.py delete mode 100644 modules/processing/parsers/CAPE/deprecated/Nymaim.py delete mode 100644 modules/processing/parsers/CAPE/deprecated/PredatorPain.py delete mode 100644 modules/processing/parsers/CAPE/deprecated/_ShadowTech.py delete mode 100644 modules/processing/parsers/CAPE/deprecated/_VirusRat.py delete mode 100644 modules/processing/parsers/CAPE/deprecated/_jRat.py delete mode 100644 modules/processing/parsers/CAPE/deprecated/unrecom.py delete mode 100644 modules/processing/parsers/CAPE/deprecated/xRAT.py delete mode 100644 modules/processing/parsers/CAPE/test_cape.py delete mode 100644 modules/processing/parsers/MACO/AgentTesla.py delete mode 100644 modules/processing/parsers/MACO/AsyncRAT.py delete mode 100644 modules/processing/parsers/MACO/AuroraStealer.py delete mode 100644 modules/processing/parsers/MACO/Azorult.py delete mode 100644 modules/processing/parsers/MACO/BackOffLoader.py delete mode 100644 modules/processing/parsers/MACO/BackOffPOS.py delete mode 100644 modules/processing/parsers/MACO/BitPaymer.py delete mode 100644 modules/processing/parsers/MACO/BlackDropper.py delete mode 100644 modules/processing/parsers/MACO/BlackNix.py delete mode 100644 modules/processing/parsers/MACO/Blister.py delete mode 100644 modules/processing/parsers/MACO/BruteRatel.py delete mode 100644 modules/processing/parsers/MACO/BuerLoader.py delete mode 100644 modules/processing/parsers/MACO/BumbleBee.py delete mode 100644 modules/processing/parsers/MACO/Carbanak.py delete mode 100644 modules/processing/parsers/MACO/ChChes.py delete mode 100644 modules/processing/parsers/MACO/CobaltStrikeBeacon.py delete mode 100644 modules/processing/parsers/MACO/CobaltStrikeStager.py delete mode 100644 modules/processing/parsers/MACO/DCRat.py delete mode 100644 modules/processing/parsers/MACO/DarkGate.py delete mode 100644 modules/processing/parsers/MACO/DoppelPaymer.py delete mode 100644 modules/processing/parsers/MACO/DridexLoader.py delete mode 100644 modules/processing/parsers/MACO/Emotet.py delete mode 100644 modules/processing/parsers/MACO/Enfal.py delete mode 100644 modules/processing/parsers/MACO/EvilGrab.py delete mode 100644 modules/processing/parsers/MACO/Fareit.py delete mode 100644 modules/processing/parsers/MACO/Formbook.py delete mode 100644 modules/processing/parsers/MACO/Greame.py delete mode 100644 modules/processing/parsers/MACO/GuLoader.py delete mode 100644 modules/processing/parsers/MACO/Hancitor.py delete mode 100644 modules/processing/parsers/MACO/HttpBrowser.py delete mode 100644 modules/processing/parsers/MACO/IcedID.py delete mode 100644 modules/processing/parsers/MACO/IcedIDLoader.py delete mode 100644 modules/processing/parsers/MACO/KoiLoader.py delete mode 100644 modules/processing/parsers/MACO/Latrodectus.py delete mode 100644 modules/processing/parsers/MACO/LokiBot.py delete mode 100644 modules/processing/parsers/MACO/Lumma.py delete mode 100644 modules/processing/parsers/MACO/NanoCore.py delete mode 100644 modules/processing/parsers/MACO/Nighthawk.py delete mode 100644 modules/processing/parsers/MACO/Njrat.py delete mode 100644 modules/processing/parsers/MACO/Oyster.py delete mode 100644 modules/processing/parsers/MACO/Pandora.py delete mode 100644 modules/processing/parsers/MACO/PhemedroneStealer.py delete mode 100644 modules/processing/parsers/MACO/PikaBot.py delete mode 100644 modules/processing/parsers/MACO/PlugX.py delete mode 100644 modules/processing/parsers/MACO/PoisonIvy.py delete mode 100644 modules/processing/parsers/MACO/Punisher.py delete mode 100644 modules/processing/parsers/MACO/QakBot.py delete mode 100644 modules/processing/parsers/MACO/QuasarRAT.py delete mode 100644 modules/processing/parsers/MACO/Quickbind.py delete mode 100644 modules/processing/parsers/MACO/RCSession.py delete mode 100644 modules/processing/parsers/MACO/REvil.py delete mode 100644 modules/processing/parsers/MACO/RedLeaf.py delete mode 100644 modules/processing/parsers/MACO/RedLine.py delete mode 100644 modules/processing/parsers/MACO/Remcos.py delete mode 100644 modules/processing/parsers/MACO/Retefe.py delete mode 100644 modules/processing/parsers/MACO/Rhadamanthys.py delete mode 100644 modules/processing/parsers/MACO/Rozena.py delete mode 100644 modules/processing/parsers/MACO/SmallNet.py delete mode 100644 modules/processing/parsers/MACO/SmokeLoader.py delete mode 100644 modules/processing/parsers/MACO/Socks5Systemz.py delete mode 100644 modules/processing/parsers/MACO/SparkRAT.py delete mode 100644 modules/processing/parsers/MACO/SquirrelWaffle.py delete mode 100644 modules/processing/parsers/MACO/Stealc.py delete mode 100644 modules/processing/parsers/MACO/Strrat.py delete mode 100644 modules/processing/parsers/MACO/TSCookie.py delete mode 100644 modules/processing/parsers/MACO/TrickBot.py delete mode 100644 modules/processing/parsers/MACO/UrsnifV3.py delete mode 100644 modules/processing/parsers/MACO/VenomRat.py delete mode 100644 modules/processing/parsers/MACO/WarzoneRAT.py delete mode 100644 modules/processing/parsers/MACO/XWorm.py delete mode 100644 modules/processing/parsers/MACO/XenoRAT.py delete mode 100644 modules/processing/parsers/MACO/Zloader.py delete mode 100644 modules/processing/parsers/MACO/__init__.py delete mode 100644 modules/processing/parsers/MACO/test_maco.py delete mode 100644 modules/processing/parsers/RATDecoders/__init__.py delete mode 100644 modules/processing/parsers/RATDecoders/test_rats.py delete mode 100644 modules/processing/parsers/__init__.py delete mode 100644 modules/processing/parsers/malduck/LICENSE delete mode 100644 modules/processing/parsers/malduck/README.md delete mode 100644 modules/processing/parsers/malduck/__init__.py delete mode 100644 modules/processing/parsers/malduck/test_malduck.py delete mode 100644 modules/processing/parsers/mwcp/SmokeLoader.py delete mode 100644 modules/processing/parsers/mwcp/__init__.py delete mode 100644 modules/processing/parsers/mwcp/test_mwcp.py delete mode 100644 tests/test_aplib.py delete mode 100644 tests_parsers/readme.md delete mode 100644 tests_parsers/test_agenttesla.py delete mode 100644 tests_parsers/test_asyncrat.py delete mode 100644 tests_parsers/test_aurorastealer.py delete mode 100644 tests_parsers/test_blackdropper.py delete mode 100644 tests_parsers/test_bumblebee.py delete mode 100644 tests_parsers/test_carbanak.py delete mode 100644 tests_parsers/test_cobaltstrikebeacon.py delete mode 100644 tests_parsers/test_darkgate.py delete mode 100644 tests_parsers/test_icedid.py delete mode 100644 tests_parsers/test_koiloader.py delete mode 100644 tests_parsers/test_latrodectus.py delete mode 100644 tests_parsers/test_lumma.py delete mode 100644 tests_parsers/test_nanocore.py delete mode 100644 tests_parsers/test_njrat.py delete mode 100644 tests_parsers/test_oyster.py delete mode 100644 tests_parsers/test_pikabot.py delete mode 100644 tests_parsers/test_qakbot.py delete mode 100644 tests_parsers/test_quickbind.py delete mode 100644 tests_parsers/test_redline.py delete mode 100644 tests_parsers/test_smokeloader.py delete mode 100644 tests_parsers/test_snake.py delete mode 100644 tests_parsers/test_sparkrat.py delete mode 100644 tests_parsers/test_stealc.py delete mode 100644 tests_parsers/test_zloader.py diff --git a/.github/workflows/python-package-windows.yml b/.github/workflows/python-package-windows.yml index 061dd2476ae..5b8daa86df2 100644 --- a/.github/workflows/python-package-windows.yml +++ b/.github/workflows/python-package-windows.yml @@ -15,7 +15,7 @@ jobs: timeout-minutes: 20 strategy: matrix: - python-version: ["3.10", "3.11"] + python-version: ["3.10"] steps: - name: Check out repository code diff --git a/.github/workflows/python-package.yml b/.github/workflows/python-package.yml index d271e493800..ac7653f1937 100644 --- a/.github/workflows/python-package.yml +++ b/.github/workflows/python-package.yml @@ -15,7 +15,7 @@ jobs: timeout-minutes: 20 strategy: matrix: - python-version: ["3.10", "3.11"] + python-version: ["3.10"] steps: - name: Check out repository code uses: actions/checkout@v4 @@ -42,18 +42,6 @@ jobs: - name: Run unit tests run: poetry run python -m pytest --import-mode=append - - name: See if any parser changed - uses: dorny/paths-filter@v3 - id: changes - with: - filters: | - src: - - 'modules/processing/parsers/CAPE/*.py' - - - name: Test parsers only if any parser changed - if: steps.changes.outputs.src == 'true' - run: poetry run python -m pytest tests_parsers -s --import-mode=append - format: runs-on: ubuntu-latest timeout-minutes: 20 diff --git a/changelog.md b/changelog.md index eadbd064d4e..48e6f7c26ed 100644 --- a/changelog.md +++ b/changelog.md @@ -1,3 +1,11 @@ +### [01.11.2024] Parsers +* Malware config parsers aka parsers are moved out of core of CAPE. + * Now they are at their own [repository](https://github.com/CAPESandbox/CAPE-parsers). + * Feature added. `load=X`, where `X` is one of those: all/core/community + * All = core and community + * Exclude parsers. Allows to not load some particular parsers. `exclude_parsers=["name1", "name2"]` + * Your custom parsers from `custom/parsers/` will still load and overwrite cape carser if name matches. + ### [04.10.2024] * Monitor update: Add GetClassObject hook to handle UAC bypass technique using CMSTPLUA COM object * PrivateLoader direct syscall capture diff --git a/lib/cuckoo/common/aplib.py b/lib/cuckoo/common/aplib.py deleted file mode 100644 index 544faf5166b..00000000000 --- a/lib/cuckoo/common/aplib.py +++ /dev/null @@ -1,162 +0,0 @@ -#!/usr/bin/env python3 -"""A pure Python module for decompressing aPLib compressed data - -Adapted from the original C source code from http://ibsensoftware.com/files/aPLib-1.1.1.zip -Approximately 20 times faster than other Python implementations. -Compatible with both Python 2 and 3. -""" -import struct -from binascii import crc32 -from io import BytesIO - -__all__ = ["APLib", "decompress"] -__version__ = "0.6" -__author__ = "Sandor Nemes" - - -class APLib: - - __slots__ = "source", "destination", "tag", "bitcount", "strict" - - def __init__(self, source, strict=True): - self.source = BytesIO(source) - self.destination = bytearray() - self.tag = 0 - self.bitcount = 0 - self.strict = bool(strict) - - def getbit(self): - # check if tag is empty - self.bitcount -= 1 - if self.bitcount < 0: - # load next tag - self.tag = ord(self.source.read(1)) - self.bitcount = 7 - - # shift bit out of tag - bit = self.tag >> 7 & 1 - self.tag <<= 1 - - return bit - - def getgamma(self): - result = 1 - - # input gamma2-encoded bits - while True: - result = (result << 1) + self.getbit() - if not self.getbit(): - break - - return result - - def depack(self): - r0 = -1 - lwm = 0 - done = False - - try: - - # first byte verbatim - self.destination += self.source.read(1) - - # main decompression loop - while not done: - if self.getbit(): - if self.getbit(): - if self.getbit(): - offs = 0 - for _ in range(4): - offs = (offs << 1) + self.getbit() - - if offs: - self.destination.append(self.destination[-offs]) - else: - self.destination.append(0) - - lwm = 0 - else: - offs = ord(self.source.read(1)) - length = 2 + (offs & 1) - offs >>= 1 - - if offs: - for _ in range(length): - self.destination.append(self.destination[-offs]) - else: - done = True - - r0 = offs - lwm = 1 - else: - offs = self.getgamma() - - if lwm == 0 and offs == 2: - offs = r0 - length = self.getgamma() - - for _ in range(length): - self.destination.append(self.destination[-offs]) - else: - if lwm == 0: - offs -= 3 - else: - offs -= 2 - - offs <<= 8 - offs += ord(self.source.read(1)) - length = self.getgamma() - - if offs >= 32000: - length += 1 - if offs >= 1280: - length += 1 - if offs < 128: - length += 2 - - for _ in range(length): - self.destination.append(self.destination[-offs]) - - r0 = offs - - lwm = 1 - else: - self.destination += self.source.read(1) - lwm = 0 - - except (TypeError, IndexError): - if self.strict: - raise RuntimeError("aPLib decompression error") - - return bytes(self.destination) - - def pack(self): - raise NotImplementedError - - -def decompress(data, strict=False): - packed_size = None - packed_crc = None - orig_size = None - orig_crc = None - - if data.startswith(b"AP32") and len(data) >= 24: - # data has an aPLib header - header_size, packed_size, packed_crc, orig_size, orig_crc = struct.unpack_from("=IIIII", data, 4) - data = data[header_size : header_size + packed_size] - - if strict: - if packed_size is not None and packed_size != len(data): - raise RuntimeError("Packed data size is incorrect") - if packed_crc is not None and packed_crc != crc32(data): - raise RuntimeError("Packed data checksum is incorrect") - - result = APLib(data, strict=strict).depack() - - if strict: - if orig_size is not None and orig_size != len(result): - raise RuntimeError("Unpacked data size is incorrect") - if orig_crc is not None and orig_crc != crc32(result): - raise RuntimeError("Unpacked data checksum is incorrect") - - return result diff --git a/lib/cuckoo/common/blzpack.py b/lib/cuckoo/common/blzpack.py deleted file mode 100644 index 03b6a371c25..00000000000 --- a/lib/cuckoo/common/blzpack.py +++ /dev/null @@ -1,89 +0,0 @@ -# included from https://github.com/sysopfb/brieflz - -import binascii -import os -import struct -import zlib -from ctypes import byref, c_int, cdll, create_string_buffer - -CURR_DIR = os.path.abspath(os.path.dirname(__file__)) -LIB_PATH = os.path.join(CURR_DIR, "blzpack_lib.so") -brieflz = cdll.LoadLibrary(LIB_PATH) - - -DEFAULT_BLOCK_SIZE = 1024 * 1024 - - -def compress_data(data, blocksize, level): - compressed_data = "" - while len(data) > 0: - buf = create_string_buffer(data[:blocksize]) - cb = c_int(len(buf)) - cbOut = brieflz.blz_max_packed_size(blocksize) - packed = create_string_buffer(cbOut) - workmem = create_string_buffer(brieflz.blz_workmem_size_level(blocksize, 1)) - cbOut = c_int(cbOut) - retval = brieflz.blz_pack_level(byref(buf), byref(packed), cb, byref(workmem), level) - if retval > 0: - temp = packed.raw[:retval] - tempret = ( - struct.pack( - ">IIIIII", - 1651276314, - level, - len(temp), - zlib.crc32(temp) % (1 << 32), - len(buf), - zlib.crc32(data[:blocksize]) % (1 << 32), - ) - + temp - ) - compressed_data += tempret - else: - print("Compression Error") - return None - data = data[blocksize:] - return compressed_data - - -def decompress_data(data, blocksize=DEFAULT_BLOCK_SIZE, level=1): - decompressed_data = b"" - # max_packed_size = brieflz.blz_max_packed_size(blocksize) - - (magic, level, packedsize, crc, hdr_depackedsize, crc2) = struct.unpack_from(">IIIIII", data) - data = data[24:] - while magic == 0x626C7A1A and len(data) > 0: - compressed_data = create_string_buffer(data[:packedsize]) - workdata = create_string_buffer(blocksize) - depackedsize = brieflz.blz_depack(byref(compressed_data), byref(workdata), c_int(hdr_depackedsize)) - if depackedsize != hdr_depackedsize: - print("Decompression error") - print(f"DepackedSize: {depackedsize}\nHdrVal: {hdr_depackedsize}") - return None - decompressed_data += workdata.raw[:depackedsize] - data = data[packedsize:] - if len(data) > 0: - (magic, level, packedsize, crc, hdr_depackedsize, crc2) = struct.unpack_from(">IIIIII", data) - data = data[24:] - else: - break - return decompressed_data - - -def main(): - # blocksize = DEFAULT_BLOCK_SIZE - blocksize = 100 - level = 1 - data = "This is a test of brieflz compression" * 100 - retval = compress_data(data, blocksize, level) - if retval is not None: - print("Compression SUCCESS!\nCompressed Data: ") - print(binascii.hexlify(retval)) - retval = decompress_data(retval, blocksize, level) - if retval is not None and retval == data: - print("Decompress SUCCESS!\nDecompress Data: ") - print(retval) - - -if __name__ == "__main__": - main() diff --git a/lib/cuckoo/common/blzpack_lib.so b/lib/cuckoo/common/blzpack_lib.so deleted file mode 100755 index 5c12be5afea5aaca0195880a1eb4e6a01b5146d2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 33368 zcmeHw4}4VBo$tL#2m{32L8C@No!YTYTFFZ=+Ki~=!UWF6JCN!qw5AD=fKY*?$(;$> zG{#N>xjTDZy1U)=?RNWoue)vC*KO_YTLinsga84o%AXh&LqM!LL$sjAh#F@0`#blZ zWD)}P?dS7$KkxI&&F7nQ&+nY`JLmk)@BGg1oO_e|Xqmn!O_n8brAv276noljQ%aqL z72kDk5R^(K(lq>@EzRP2Ge(mxxO;M{O%kEx@TEGYP?8fLAI_O;mlL5#r*gc$aywlb z7q(>EbP=YO%S4iUlb!Bv9viYWJ6`UDq8vr3oX08WamtCX!x5bbT{auuMrvn?!*6`( zb@GXj_X)J}w~QLPZ~3O3VSM-_r<@2yxv!%fwe#~{LhScA^<7LZXPy3u(24T?<)E^3 zVDZxXq)%o%rYsw*{>`W5(#`el=G}Wv_H&6*`gDNGQTx0Lr~c)a%v?^JfjG6}Cr@~P z@#MWfI9~kBtmO5lxBudv{3Wi3K1lx)mN93#=eo5E%76XK|NX(=zETkR>8>hdpYX~= z1(#2dLi{}w(AR=CQT~rFLZ^x+%AdFho%-tm#$Pvs;2BRud=YTt1oSV1(dAN>BrUKL zuXplfJM>bYP57y!cv}(W`ERo6VdSIh&jF&he2GV;upLN^4*f}|@^3o&`jkVLzHDdw z5e+1+PJsB7-pZqVOzCcx)1I@cO{cM?>urGYuXOVFIDC#c^m2!O8D+-x&j96r@+&+l zJxR(#S5?)68*4XJH5jYvjjAfCN(%<6YSz@Rd2oG$v8Fy4Sh%5f)0*I_)f?8>X%nYZ zRc~HZwRZicRU6hnvPRmlesy(0Lv6ur(#AC#8`c=81pKQXs;XZ1P}SO1>o-WNH#~w` z>WJ2`YVDeoIKOSIt$zqbs~W(qYQviF8oLDL=jpuQC_ObhPv5v|a~0)TQ^Q$Eb*t(h zta@;bQCnwJp+65w4Mu(Sx_TZo)NP`0Q}xC=J74{p+ImPJwUB+ke$#qGTC8ge7FNwI zC?2_+Tfk*a1Dr0U@gEXw8s_FiKa@uEHch$@p|BS@>(^tb(xoDdH_<}ZuAfFc<{?g( zu&crjuAFJpa~-=W=pKh&-eRW~A)TU=5a8!~LVkvZIY2oyS>tfL8 z$jO_2kKf7-rMRQ`I!cS5Oyauf7{$qjiXYE#AT72PsajRQzck-%W9Hq2f>S z__Guz7b(7t$N!n)Es3*KR|cU(CAme}cfQDStzO@0@WZntm1Cqv_Luo?NTk;2$kd@@ctq z4$4ZQuinQZckZTbEi>OTvRL%aY|vxhKr>@C__c4!6vX9kq3)6TseHT%f0tT zKAoyO{x4t?UF>1jWjhx^wA=gq%Jz(JDBJaK$ZZFdHZLR^Iqm8^>GE4klICKM-(2Qx zJEF8kQ4ai3)a;ZyI^zn`B5%m*#~ny$QQA%*h@4JaYGtVAa&H;&`WZ+py4cMk=VWEe zE*`s@MPg~pTSpEx=vJwu^60>7 z<%U*}NBM@oZOe^CFV5NAEq9=`ou?J2wV_*4Z8o@|wF{o5n~{2rcIvm&>9%YLQ1qbj zM@1df7Q6nVC-V&*G4>?V~?XkC| z76}4#hujZz*>d3R!8j2=V$1m%zm6_*V{pvnIacvBj2#BfY;-eue_2~cXgg%5JTu)M zjT~n*lxGghN6h8!wQUC;{s|u%r;#>CrS$=bX5i$!H?Q^&(KiqBUm&<&B zzpcl&+2n+wgu z)Czxor*<^%x0|GP#!(leMx```2GlBbtNDkh6KE4u4_4=Zqo35ylnJ0NSMOKvQ-k;2 z%N~2T9T}Nvco{Q;UQZ2+X55s=Nq+CSmoW<)$R`9+6Jgc`{wIf>SVrb9M7ty2ZfX z&dj-LB$;MhMFcm}n0Y%08KEhfX-vu0B3&}rhkmxq$|>H#8AqGE9u++DKL*>gEQ(fP zMNuAm+o|cSF8_f=vsvVmq|$l{Dd;mNVapa9p!8W(TaStOc-Cg=$I0HKE?34zj;x%J$i5WhJxaP!?2EX1?ywyUaYN zTX)NvuTzN>P<@eein298cV?Gn?nfP=A2Dm;upXsGM9$44us}W&)30zF&dWw2P z?L%s6G4@qIW;wELu3@*#=CfRBYr-J1$M%pFc;H)Vh59YEQmyJz+BQRYni<#30WJSP zAiqoNjHd^D&nw@rLIPK&E&oFDCG8<~f>J?6nAMPgn#A9x(vT8Tv#f=-cD!zU(QbXv z>%#JtDs@%aetEk)UJTR7Tg`h<9UmuQu&cX3iKy=b|44Iur!&Vftw-m$-&@G6ti9+T zl-Pe6X1ZH9bLkc{y^xu1G1L8*L1eJ+g<_@$FGIFPvdz`1MTfeea(-{g!l=Jk=H>(1 zk9j^?S*I??h)LvAO!FPXkdMXSK|nlyZz-5Tm;K%q%(^=X)9QO6oTFLAvo$L#2Xp$4 z+e%BCW+aUY=6kiik#u#1Zobc~@1oKsOws(qdj3AxWB8`lBVg3zEr;B0S4*05lE$NK zp5N;ZXEF02>pY##d>_@X3ccRCHtq*<0HL$B(0*d;-l2dfkm) zR2$mCpf1e!zOF3td&`-!=-9wNKpjct<8H1tL^h8O{8{X!50lB1wTb(a6Rl4xXf~DT zkRQ`AOUfr)sh%9SQbA1PSE}zJ3sKj>0`s+s%u*ex2Ns}oWy?R)gs^Tt&M9WUX1>U* z+4;=Mxs5^73Yk1WVJUm;Q!?$!)_cJZt67@#8#=vaSO}nRIb7fP%18Q2!irsmj*@nl zh_x-xz-&Z(rw7S8tywBxO!8l2*5>m?9V7mm-`uS#zsi})j-J-69QXutHM1CA4V-kc z_UA(V#HW-+n!I_^uKD1$R;it`&6=IfApKlD%1s=!qhlH~)9w06&p%<-qg=~9 zteYRAYmsx93mO_hnOMNOS<&HP?ts{&fiLiV)v{>DK0Diu$fiY3%Nn0RIaJ8EH+ud%DsVqr8z$h~tIOJIsue9@*mAuWbD(b;0~p zH9w?j<5K^PD%bOOYu%mD>m+6jIs(U2`Rx%F`CvY@BS+0Y8mNBVk%v{DFtM=Psrj$4 z>Q`9wjxJq3#;oA-X`1hFI8!tCXmHo~fOIyzKq7SMz8T>H>UAMmvRvJqp_>`pE_-y- z6TsHejb3HUUs&Rw3K@NuG!OF^)2O^*772x!`?*}&Vwk$48yMDx+zNFVy~&FQ$ZT?l ziZ8Cvf)YMBSk)GBCu*g#eX-oWC_Ut{v)S%3v>q9zkVRUFW-Lx?Uz7nmVXt^g`HDxq zSl2cb`bzuN)Qxp~K^j?7uvF7Mvle3|LPpNX@?S0=Jqez5?NfP~k?gc+f0e8sDxnpq z*ja&YoNxt#w0nO;s!Ritf7E;pn~?aAVQI+U_U%``e*^Uz(lR^a2XRZ|twUuY>J8q~ zq9eO#&gsz_Z;ARFND5P$Jd18@^(canh;b9Y)^5|R2Y7ey{%XZ>3EjPwH~bPSJnuI8 zxDMmZSK*afG}8)RE;Fkx0qv=a{r3;3b^RlLi%D^aaMW*U&kdwsFXSEY^@Z6|%Q!As zOJR63`L4W;&JValFl5}q3y)hi;acR}(C!|~r*Q{Z#P1^M(2#xJUJU$%vggry4iUn@ zEwOSuORbQ4 zJoX^ zi=2_;Ipk`XFU7ME#(wtR$iC^`wM^O6O}`G(ufuDV4V^fzDjl;Vl)yL6$C^kv_94e^ z7~(=2e4=_7&Oll-pn0Gc6P20I7jE{16%LKT770f} zO6yZJ`$%AdoX5$3&dFE?xvyX?;Qj)i@wv>xrj1M|_jPpN>&ljgkQ+RT!5NH;X@{&j zd_7zPwk#0*?2{QZLmbVZnC(iVvXu6=mXke$uEWXcjr{~Nqt<>#ov;kAEA|7266f8z z!%KaD*S!o&2_5}pd1(^6*qu-xtZiL97xmeyN9VEf^Znp29I_kRCzocvid1yX@Ve18 zCd19$lmZ$h2BZg$!A;J)8Lsh2CV*EUzX%AOA;g1X|EEl4)W5Yol?kyNjE7 z&`V%=GPvOhVKcU;R5xFJpbNu3a4NQF05+DdN2B`nB2F_L?Hao^&MoSI=D4L&(x(hB z7t3WBEX_Q!gNP`{%y*C_hZL?`RFik7Khj$Z*JYYeibjP4^HHSte$EU1ptcyO;?c z+p(8`Cr;;`ANMl3H_-OFF^^eG&@hYz6cugB#?eaTv!wAwUGC@S9H8{F)pAPC;&=u;QJAM-56gwDCUEd;!4CA5Z zFGT(@C6buZsKT9^4|j`vtgxS18Mo7}oz7jb=6R$@B0ZFem|ueFewGdun7x^1%Cg-y z-60@ipND}5yc+k&c`W#pN?oJtYs&dZz-0Vn%`a}mvana)L+d7j$` z=UhaKoX5Gy8#ICWp~y>=n5UTtF^#!vXt$QH+-@3LBoy++Dt0+IZD)& zg)bBhu}C~aX?+!O=c5VTHFl3|Ndo5VZZbv45qd+n^y?%w zN;{X79MNLrNWjIfL{qKBNjO!s^)4nK8D3V&0R7C0pAvzP~3R@?Gn6$Voc~l z=6g+v(0R7zJKlH~mWcQ^v~X0OoCPtEhin%1*4=}>_I226qZIbq4llI8u03>sisezU z(snFKxQD(LI(uLb*==qBoy~S0mp$i*y>=n?+SHh*M%XT+m9&^tKCdkq`f6$WT+UK> zG&WyYI^G{^0c;_1@}aW)x7i*|VSCyI%^;5k`&6A9mMq7kxt9h#vWKN^s7XHq=IOGc zjwP1=R!Pf07MdBixQ&9x+kx|>-NuZ?%66~3sKhH7@51lPP_~?c9C1jK#A1ql^;yl_ zH!2_Q66A5&7?2Hgr+qCy9~hAh?+c^}A=++=hx$UR1E%4NWNWeA#gxWPVeB1DLERi0 z@mO9#oVx4L@ypG1jrs{wRVV9mm!kuP@sF`Mr_A>W8$>!qjTsp<(Wv-OPo9;x>>T&vXmY7l4AUY>*s;uCV$Ck1y`o2#!L0&%;_Ml>M3GZde*4PK z5eN6MiUZQ4C&}T)Vwe8Zxnt8(6U_AFXFNF=2-4HPXBhw#r~%clDdHN1%}7rJKYx1!d( ze4jL6YuF7hmam(>L*awu&A7FBB@KK}<GN_9OL+zQ9p)C z;?Vfh*uW{82oPq4m!+KLh4G>o?9Phuc8BY?ahQ(q`8qXLv5g(}0!4~#zGSaSWD)oh zrT&%=)R;A@GV#5WE&ZLTCbv5 zk2K|1II)T=kG(<1DVjO^cVzK(-$3Y%C6+!%iWVWq2e3-cSvsU^>qc891f)gw%5Y6F za(;SHF%RlOCcY5Q6zM?3ali{e7a@f(6Se>e;!(qsfO3^}rTdK`D`zBN2PhGDdYqS#_gL9Htuu8FD zQB$58$Cie?1iZfjXBg~C#ClcA*Fl5U<3(7jkcoQ_R3n|8^Bs7pQwA*U>=;y9uUzpi zZnN=7jclucKB@e%%s{X3pVXZ+pr>{`1`-Pyw9aPXvoUs9ZQ=jsl6Ks4}U?9U@Hmxej5Mc%`6 z#n+X#zr{f$jUKkE8)$*5ftC%a{7iCWvtKAS`&xGfJvf)*e~Dk*Pt<9@kKqf@exIJQ z-o|Cim(q(28-}5jB#gs5dnqmCJAPVC`HsId_A|^0J!QxL*N78ajF9c_6#Cn9we;&r z2mQoO^PNz(&=Zz`Roq7pT}Sr)6;MuUAAi{T652k(2Ywi-4Y@fI2EDZ1J@AXQ+h`%k zg+qvy{Z=WE9}mrnzloC)7`s+e8p5c1Z=8e%N zJ{3P@ooAHC-f^blux5Qvrs+t>JMIP1ra3YuV@jStG-H?!sEj$xYKD_}&cN0tE^F3z z;R=2dzIurTwp8JND=RTdV9y8902)s`T-x#?S{ATENiBa!!()Tdc?8c4qj0G?G-e=# z&XZqLNb@x|8@43XmB~V!i_o?|0r_~!m=wm}gf?-#n6O@mTg+Xm$#wv6SQvi-#q9MY zU_Kvzn#^?D2GB&G@Nk_!Dq8^>e^eH~2II=lCBdlVb8A~Xov#3X%n18Il%Kbg^j5gB zMP?r^SCyZ6A3d0v0<>Qh!V5*YQU_hOBH8jwq=-%&2{g2(`11 z5pNiKjED>i`7t6gl%=&V%otH|YH)lBX*2xDq9hKureFqQ&*b;Xcz}6VXc~)jLvKC_ zy$g|ebj*nFpMdcQSb=1~{DYSNejtAzo%VYIc$P^wd30(z11AL27M18zl7`Oa!3>16 z1Lj$+GnTI7DTt>&3yi|o@<)H+E67B+R#9jDGXEbjY_C*m8qxq^IkYq3lm z@)~DRQ`&;m6!U$0^rg>3Bb2QRKw(xRs9o{9aSx@9--ibQv1zX(A+kRiUw1B=OKvFd|bRDVI@M_*5Y0E^1Z8Roq%*1eDny5v`O;nCHe6@K$jiVLxJTXdmI zeHNpb^zCgv!Kx1hqD?PLaG8xGaHMqeyKWO1TISCQ-A3oga%+b%=Z-l_Ya3VwtVZN$ zz&ZD>Mmc^Lp8$CNKqm|f-DS$Is|Fs2{W9mN&ytB24T*=5aa4XHKbT~i3$xUgJG|)L zU!jEhEP2rJ#SULQaTF|c^A_q({AMJnEsv&2O6#3uYe{Yof~L`_wRP*)zervRoxq?y z%x|exCWf zxdGcv^CKN$Ntt%{}~_+B}74+PayH?S7RG=t4QLu?t$7ut8B;r=nYa6hgHH zc!cUv;ZLx(_d*BFR|DqTRD*~7zC5UPG3j;*Eq|rdP{!8*dY`N9=OlU@tWBl%tESAV zsf(Q_r)YA=!j`75rQNAU>rewd_t}rUq>8PtrHnvXv^&H7a^yuP|&ol?uA*%?F^;h88=Y4%p91w z%YKO1HLlD;(PSw4{3Kl`nu84mb6h0A}XQfO6BYR{5@a<*M5p>STGw&VW zvA;%B;(5f?nJ4jAu)3;{(7+LhF*kmedOoVI+s5oqH$yRQrd0zfhDMFqsIDvOFwfE6 z^6|&X4A6@;AKDL9=}d{gUc+~Y7M^R+$r1FekYr_hB8Zhz3}=l2yzODenR(1_zD-Wt z-}EMvk#qBnD=-d=T3hl8|{uHQzIj z^YIzqUY}&(IU){UxKJTX$dSvF^vVse?yIY0!5}5C(UD8^)Rb`-k*Ppb-t1Ax4wy^=Nx`6Qf9uY9*&h+ z>u`p2CSb<2kB_s?chZ+yH^+6~8CCi5UgkSos{FWHbwLqcr&$ph$W$Nu49n`H%GQG* z_+h2xPc=(d&O#E0&#c|{p;DU$OjGGtJ+d2XSlqo<*>^z3uMSz6x#X-eQ+2DpPwHPr zVe?qzodn+hyCeTo6&@>0!U0x&1TSH{gtxt3Ime$I3q@`h}-tdr9;C=83~+{8p_TkYl=e2HnzdNKM@e_+n1C5OkEe_A0GCv~s0( ztBVMj!lT`SkVf_O^YyRH*IEBExR|Ha$jJoW&rJ8{@Amt;|5y)4hVCWa!$9>O^e|=U z{zF~d30`BmNGlQ=2c^mr-K0Kpdm;Kq%lAcx&+pq;-#gO1g;rL^=jk3ld5BNpD-r5H z9Up?}E;D;*>a~&=O!LiezFB6T@|$nP`)J#=4Gq-gPe$cWF91d#KBq?F^jb8|XK*HD zK5~wkMWh;yCkLLe`{9(s^Quedk8i=mgB|(Y`Drmk{xb8dYK3KMv#gr$tN9&jey2(u zdHiJvx6Haf$*T8j)xByywrHo)b!+wuprdy$AAZkot-*}L9{(-v<33W}rIz=U?t23| zxkvLIRsOD1b^T6ht>>C~8WZkQd%~^an)zn=^GY&9*5t_0;@?UfqG?wKBZK!P{?7JoWH^YTb*;`m$yo)$#C=49Y3^+Be6U z?`2i_yABOcrT%WW>N=#fK2MAye?a#VcK66H_QL{N`i!%hd<^E~J>EM(YXjB4XHQ@X;oQ>S1>=G@p9}GN zDKlN>x%d;PgqCHp+qBHgAH=%Da=o`I(bsDFB-@pogISqH?$@p8g z{@|_HE13K|^v%tpcRTvof&2r|PX_(G!q!jJR6v`Qnit95A2W}~2WdMrvj2k_#fZk& zAo+rIp6^uno5tOX`6i)Dl1BbMBqIJIgg1Ng*Q5j{B`_(0NeN6!U{V5;5}1_0qy#1< zFe!ma3H*O1fv@2efG3V8lZSxViDc4!GMV%M3|I-&0WH8;Jczn<*X;i&m4W{ZmkDG6 z*+33rR{^tu>w#k6HsB86E+8nmr2Byipb{{EFwg`v13f@5&v=m!RYAz&Ct0Kw}}9;g5+0RspFO+Yiy1M~uYKtC`D3<1MH0tnuK@<0Vp z2^c^aXabsn9-tTK1NwnMUm;AJ7jB0z<$skN|>T zLwTSAs00ik3^W1FKo8Ih^a1_AATR_B0|_8_C&~jAKqX)RVW0_U26}*ApbzK=27w`9 z7)SuY`6v%m0F{6Ngn=fY8R!9efj*!g7zBoZVITnn?{iD{0~J6eU;tsD31|j-fL@>v z=m!RYAz&Ct0Kw%b4^#k^fB}SoCZHMU0eXQxpdT0nhJaxp0R+E=@<0Vp2^c^aXabsn z9-tTK1NwnMUmpb{{EFwg`v13f@5&p>AF&yk!k;2<+@6`+I6**p7vk+lbLbppR7##C)brLUE{h&x-8TFxz=^9 zG|M$hnwoLxpX^NgXSQp$be-!uNy)T-u6JE8-Qc=Gx^tXUh-XOr65%W-F8(*>G$$?s zc~<&7dNrHUpZr(;K9%Izo=l!Z{4BzA2v_caPYQ-BcjEmN3V)MKuAmBbCzC%%=-H2a z2wM&&le6*ESo&QuS&Fa)VGyAQ|Coy2pXz`QOYdMELg>O{?~@2;Bkbr;CR-8K;blnr z|FkU#V+iTuf769fe&ilW-t3lVWleQ$LtS3bW&c+KjSnm*hbbJt-=A zCYc;Y=;Ygo42x%^wIGN6zg6g&YYyb}5%I#M1OG-h&nA;Uz^e?>f^7Gnr7g(LeLQ_Z zwg>-iDLd~^r>NP5TQb$`lE~D>*&T9vX2$gF642D_Jmf)Mlv$ANQt5yB5s! zlK(&AKgMsHoPPPledqkB%`3of&nw9!iIOg&Z2+wUH1WTXYd~uO?cYG-|2O%bv13?9 zW9X+bTxgHsHaV>k-2iFa5H6gN9!$%2b?y7z3opL3Bzv12nYtzOPp4QJkEj1x8kbiL z^%Ud9M*e@K|5*Q?meXIFSY8^*i~3T6`SX`=CX*DWi)cD%+dvcl!|2JJ>vU3I7Z`@+ z*5>W^IQj9XWIQh9c-D!ZbvlNZvw8YRJDvLfvjXuQyYcniMh7;y7CGVlPPo8=sI8B2$jIPw`w zpDuYOq|cC^oRFS1@?FNUd@hs3{2NQp#(`}r#lBC+7pBB_1yfVg(MZn&sT7fa=E!%w zQd84$YA@#TSo#&xM0%Bu*(Sd0H8%g1BlB}C{VGZ5(^&e|(u$T;ihZ9hiCH+BM)NL1 zdjEoVSICZ~!J3KhT#6Eq7^j~cC;u-vbYT}o{;%OihSd=55%YWzr(Y0faQM_Y-%;bw5J0294wv!fP3a2U(B&Asef%~{I_W%!8Rm(SbQIx4`Ok>_ zSJ)ZFa|J5L^9#Ll3}P-iPVzj7p`?pHb3j<)&|7A6vc#Vq;FjbxQNQS)$I8&drb;`1 z>hFp2FX#L()ckYn{cHdofAD$1yx8LK5#uY`L;w9zmM+xW-$34J_&O@O zFy^A?RQ$V%KASAQ*Z8lTJ|-)V90c8SAz6Cc;UnE-CyMVozVFb-f0r>0?Gex3QrTU9 z5&B$C&yvP}$MG(QKK}cW_c`?O-*;Sl5&n-{gpS7$Tt4H!L-{{IpGXeBbn=h?KIJol zzQFFSc-GMA(8qso@@3E`;(rG88&d`5+|R&5J>mB$tLu#hBZNN)y9phMn7R`M>o{gJ`}1e z*kIIF)zz;L7tH0~q!hXB2roB2W0C!F%aG0X5*Z8ajP&`;b*mcItq$Q+mqtN#?WP8! zuD-UeASHbRzOq^0fRA@pExJbylvR~2_0wlQsqZ9~hFWmgR6}3)^nYWi8qgMkiVx3L zl`*FP^WOs!J_IU?F4mVVQ1z;1ix%Bm7OV=Y3-q$8v0u(~KBrk)Dn6D;pUAw_mqkZE z2g*A(=6jywza2Wtwb=QL=O~5hN%_|21NOU)HkfJ-83drg|zxL8&**P=dNypArr+8}ZOtlUl~k~1oilsZ)qshJ*+uPXWS0>4sA1K{_0_1p)*#Mk z9OtvTp+SOLZ`_FaIf2pm50GfzM0*dIA%0!#`_WD^*3z*T{)->p(@EBf@++Mi5sKwo z>^sE1MsOjooc2CwHA4I>YD?FKqvDq@i7Fj_cZSiK1RRRg!31IW7xNTK$Nf<9(6Q3CEZJcM!zAvH$=8 diff --git a/lib/cuckoo/common/cape_utils.py b/lib/cuckoo/common/cape_utils.py index 060ae70588c..6141ed254a6 100644 --- a/lib/cuckoo/common/cape_utils.py +++ b/lib/cuckoo/common/cape_utils.py @@ -1,11 +1,9 @@ import hashlib import logging -import os import tempfile from collections.abc import Iterable, Mapping from pathlib import Path -from types import ModuleType -from typing import Dict, Tuple +from contextlib import suppress from lib.cuckoo.common.config import Config from lib.cuckoo.common.constants import CUCKOO_ROOT @@ -21,6 +19,9 @@ HAVE_PYDEEP = False +with suppress(ImportError): + from cape_parsers import load_cape_parsers, load_mwcp_parsers, load_malwareconfig_parsers # load_malduck_parsers + cape_malware_parsers = {} # Config variables @@ -47,53 +48,18 @@ print("Missed pefile library. Install it with: pip3 install pefile") HAVE_PEFILE = False +# ToDo check if enabled +HAS_MWCP = False +if process_cfg.mwcp.enabled: + malware_parsers, mwcp = load_mwcp_parsers() + HAS_MWCP = bool(malware_parsers) -def load_mwcp_parsers() -> Tuple[Dict[str, str], ModuleType]: - if not process_cfg.mwcp.enabled: - return {}, False - # Import All config parsers - try: - import mwcp - - logging.getLogger("mwcp").setLevel(logging.CRITICAL) - mwcp.register_parser_directory(os.path.join(CUCKOO_ROOT, process_cfg.mwcp.modules_path)) - _malware_parsers = {block.name.rsplit(".", 1)[-1]: block.name for block in mwcp.get_parser_descriptions(config_only=False)} - assert "MWCP_TEST" in _malware_parsers - return _malware_parsers, mwcp - except ImportError as e: - log.info("Missed MWCP -> pip3 install mwcp\nDetails: %s", e) - return {}, False - - -malware_parsers, mwcp = load_mwcp_parsers() -HAS_MWCP = bool(malware_parsers) - - -def load_malwareconfig_parsers() -> Tuple[bool, dict, ModuleType]: - if not process_cfg.ratdecoders.enabled: - return False, False, False - try: - from malwareconfig import fileparser - from malwareconfig.modules import __decoders__ - - if process_cfg.ratdecoders.modules_path: - from lib.cuckoo.common.load_extra_modules import ratdecodedr_load_decoders - - ratdecoders_local_modules = ratdecodedr_load_decoders([os.path.join(CUCKOO_ROOT, process_cfg.ratdecoders.modules_path)]) - if ratdecoders_local_modules: - __decoders__.update(ratdecoders_local_modules) - assert "TestRats" in __decoders__ - return True, __decoders__, fileparser - except ImportError: - log.info("Missed RATDecoders -> pip3 install malwareconfig") - except Exception as e: - log.error(e, exc_info=True) - return False, False, False - - -HAS_MALWARECONFIGS, __decoders__, fileparser = load_malwareconfig_parsers() +HAS_MALWARECONFIGS = False +if not process_cfg.ratdecoders.enabled: + HAS_MALWARECONFIGS, __decoders__, fileparser = load_malwareconfig_parsers() HAVE_MALDUCK = False +# ToDo move if process_cfg.malduck.enabled: try: # from malduck.extractor.loaders import load_modules @@ -118,11 +84,14 @@ def load_malwareconfig_parsers() -> Tuple[bool, dict, ModuleType]: HAVE_CAPE_EXTRACTORS = False if process_cfg.CAPE_extractors.enabled: from lib.cuckoo.common.load_extra_modules import cape_load_decoders - - cape_malware_parsers = cape_load_decoders(CUCKOO_ROOT) + cape_malware_parsers = load_cape_parsers() if cape_malware_parsers: HAVE_CAPE_EXTRACTORS = True assert "test cape" in cape_malware_parsers + # Custom overwrites core + cape_malware_parsers.update(cape_load_decoders(CUCKOO_ROOT)) + + suppress_parsing_list = ["Cerber", "Emotet_Payload", "Ursnif", "QakBot"] diff --git a/lib/cuckoo/common/integrations/lznt1.py b/lib/cuckoo/common/integrations/lznt1.py deleted file mode 100644 index 2c11586a480..00000000000 --- a/lib/cuckoo/common/integrations/lznt1.py +++ /dev/null @@ -1,132 +0,0 @@ -# Rekall Memory Forensics -# Copyright 2014 Google Inc. All Rights Reserved. -# -# Author: Michael Cohen scudette@google.com. -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 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 -# General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -# - -"""Decompression support for the LZNT1 compression algorithm. - -Reference: -http://msdn.microsoft.com/en-us/library/jj665697.aspx -(2.5 LZNT1 Algorithm Details) - -https://github.com/libyal/reviveit/ -https://github.com/sleuthkit/sleuthkit/blob/develop/tsk/fs/ntfs.c -""" -import array -import struct -from io import BytesIO - -__all__ = ["Lznt1", "lznt1"] - - -def get_displacement(offset: int) -> int: - """Calculate the displacement.""" - result = 0 - while offset >= 0x10: - offset >>= 1 - result += 1 - - return result - - -DISPLACEMENT_TABLE = array.array("B", [get_displacement(x) for x in range(8192)]) - -COMPRESSED_MASK = 1 << 15 -SIGNATURE_MASK = 3 << 12 -SIZE_MASK = (1 << 12) - 1 -TAG_MASKS = [(1 << i) for i in range(0, 8)] - - -def decompress_data(cdata: bytes) -> bytes: - """Decompresses the data.""" - block_end = 0 - - with BytesIO(cdata) as in_fd, BytesIO() as output_fd: - while in_fd.tell() < len(cdata): - block_offset = in_fd.tell() - uncompressed_chunk_offset = output_fd.tell() - - block_header = struct.unpack("= block_end: - break - - if header & mask: - pointer = struct.unpack("> (12 - displacement)) + 1 - symbol_length = (pointer & (0xFFF >> displacement)) + 3 - - output_fd.seek(-symbol_offset, 2) - data = output_fd.read(symbol_length) - - # Pad the data to make it fit. - if 0 < len(data) < symbol_length: - data = data * (symbol_length // len(data) + 1) - data = data[:symbol_length] - - output_fd.seek(0, 2) - - output_fd.write(data) - - else: - data = in_fd.read(1) - - output_fd.write(data) - - else: - # Block is not compressed - data = in_fd.read(size + 1) - output_fd.write(data) - - result = output_fd.getvalue() - - return result - - -class Lznt1: - """ - Implementation of LZNT1 decompression. Allows to decompress data compressed by RtlCompressBuffer - .. code-block:: python - from malduck import lznt1 - lznt1(b"\x1a\xb0\x00compress\x00edtestda\x04ta\x07\x88alot") - :param buf: Buffer to decompress - :type buf: bytes - :rtype: bytes - """ - - def decompress(self, buf: bytes) -> bytes: - return decompress_data(buf) - - __call__ = decompress - - -lznt1 = Lznt1() diff --git a/modules/processing/parsers/CAPE/AgentTesla.py b/modules/processing/parsers/CAPE/AgentTesla.py deleted file mode 100644 index b3c8146054c..00000000000 --- a/modules/processing/parsers/CAPE/AgentTesla.py +++ /dev/null @@ -1,74 +0,0 @@ -from contextlib import suppress - -from lib.cuckoo.common.integrations.strings import extract_strings - - -def extract_config(data): - config_dict = {} - with suppress(Exception): - if data[:2] == b"MZ": - lines = extract_strings(data=data, on_demand=True, minchars=3) - if not lines: - return - else: - lines = data.decode().split("\n") - base = next(i for i, line in enumerate(lines) if "Mozilla/5.0" in line) - if not base: - return - for x in range(1, 32): - # Data Exfiltration via Telegram - if "api.telegram.org" in lines[base + x]: - config_dict["Protocol"] = "Telegram" - config_dict["C2"] = lines[base + x] - config_dict["Password"] = lines[base + x + 1] - break - # Data Exfiltration via Discord - elif "discord" in lines[base + x]: - config_dict["Protocol"] = "Discord" - config_dict["C2"] = lines[base + x] - break - # Data Exfiltration via FTP - elif "ftp:" in lines[base + x]: - config_dict["Protocol"] = "FTP" - config_dict["C2"] = lines[base + x] - config_dict["Username"] = lines[base + x + 1] - config_dict["Password"] = lines[base + x + 2] - break - # Data Exfiltration via SMTP - elif "@" in lines[base + x]: - config_dict["Protocol"] = "SMTP" - if lines[base + x - 2].isdigit() and len(lines[base + x - 2]) <= 5: # check if length <= highest Port 65535 - # minchars 3 so Ports < 100 do not appear in strings / TBD: michars < 3 - config_dict["Port"] = lines[base + x - 2] - elif lines[base + x - 2] in {"true", "false"} and lines[base + x - 3].isdigit() and len(lines[base + x - 3]) <= 5: - config_dict["Port"] = lines[base + x - 3] - config_dict["C2"] = lines[base + +x - 1] - config_dict["Username"] = lines[base + x] - config_dict["Password"] = lines[base + x + 1] - if "@" in lines[base + x + 2]: - config_dict["EmailTo"] = lines[base + x + 2] - break - # Get Persistence Payload Filename - for x in range(2, 22): - if ".exe" in lines[base + x]: - config_dict["Persistence_Filename"] = lines[base + x] - break - # Get External IP Check Services - externalipcheckservices = [] - for x in range(-4, 19): - if "ipify.org" in lines[base + x] or "ip-api.com" in lines[base + x]: - externalipcheckservices.append(lines[base + x]) - if externalipcheckservices: - config_dict["ExternalIPCheckServices"] = externalipcheckservices - - # Data Exfiltration via HTTP(S) - temp_match = ["http://", "https://"] # TBD: replace with a better url validator (Regex) - if "Protocol" not in config_dict.keys(): - for index, string in enumerate(lines[base:]): - if string == "Win32_BaseBoard": - for x in range(1, 8): - if any(s in lines[base + index + x] for s in temp_match): - config_dict["Protocol"] = "HTTP(S)" - config_dict["C2"] = lines[base + index + x] - break - return config_dict diff --git a/modules/processing/parsers/CAPE/AsyncRAT.py b/modules/processing/parsers/CAPE/AsyncRAT.py deleted file mode 100644 index 1220071ea7d..00000000000 --- a/modules/processing/parsers/CAPE/AsyncRAT.py +++ /dev/null @@ -1,5 +0,0 @@ -from rat_king_parser.rkp import RATConfigParser - - -def extract_config(data: bytes): - return RATConfigParser(data).report.get("config", {}) diff --git a/modules/processing/parsers/CAPE/AuroraStealer.py b/modules/processing/parsers/CAPE/AuroraStealer.py deleted file mode 100644 index ef72590eebf..00000000000 --- a/modules/processing/parsers/CAPE/AuroraStealer.py +++ /dev/null @@ -1,73 +0,0 @@ -# Derived from https://github.com/RussianPanda95/Configuration_extractors/blob/main/aurora_config_extractor.py -# A huge thank you to RussianPanda95 - -import base64 -import json -import logging -import re - -log = logging.getLogger(__name__) -log.setLevel(logging.INFO) - -patterns = [ - rb"[A-Za-z0-9+/]{4}(?:[A-Za-z0-9+/]{4})*(?=[0-9]+)", - rb"(?:[A-Za-z0-9+/]{4}){2,}(?:[A-Za-z0-9+/]{2}[AEIMQUYcgkosw048]=|[A-Za-z0-9+/][AQgw]==)", -] - - -def extract_config(data): - config_dict = {} - matches = [] - for pattern in patterns: - matches.extend(re.findall(pattern, data)) - - matches = [match for match in matches if len(match) > 90] - - # Search for the configuration module in the binary - config_match = re.search(rb"eyJCdWlsZElEI[^&]{0,400}", data) - if config_match: - matched_string = config_match.group(0).decode("utf-8") - decoded_str = base64.b64decode(matched_string).decode() - for item in decoded_str.split(","): - key = item.split(":")[0].strip("{").strip('"') - value = item.split(":")[1].strip('"') - if key == "IP": - key = "C2" - if value: - config_dict[key] = value - - grabber_found = False - - # Extracting the modules - for match in matches: - match_str = match.decode("utf-8") - decoded_str = base64.b64decode(match_str) - - if b"DW" in decoded_str: - data_dict = json.loads(decoded_str) - for elem in data_dict: - if elem["Method"] == "DW": - config_dict["Loader module"] = elem - - if b"PS" in decoded_str: - data_dict = json.loads(decoded_str) - for elem in data_dict: - if elem["Method"] == "PS": - config_dict["PowerShell module"] = elem - - if b"Path" in decoded_str: - grabber_found = True - break - else: - grabber_match = re.search(b"W3siUGF0aCI6.{116}", data) - if grabber_match: - encoded_string = grabber_match.group(0) - decoded_str = base64.b64decode(encoded_string) - grabber_str = decoded_str[:95].decode("utf-8", errors="ignore") - cleanup_str = grabber_str.split("[")[-1].split("]")[0] - - if not grabber_found: - grabber_found = True - config_dict["Grabber"] = cleanup_str - - return config_dict diff --git a/modules/processing/parsers/CAPE/Azorult.py b/modules/processing/parsers/CAPE/Azorult.py deleted file mode 100644 index e3c886b5a82..00000000000 --- a/modules/processing/parsers/CAPE/Azorult.py +++ /dev/null @@ -1,80 +0,0 @@ -# Copyright (C) 2019 Kevin O'Reilly (kevoreilly@gmail.com) -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU 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 General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import struct - -import pefile -import yara - -DESCRIPTION = "Azorult configuration parser." -AUTHOR = "kevoreilly" - -rule_source = """ -rule Azorult -{ - meta: - author = "kevoreilly" - description = "Azorult Payload" - cape_type = "Azorult Payload" - strings: - $ref_c2 = {6A 00 6A 00 6A 00 6A 00 68 ?? ?? ?? ?? FF 55 F0 8B D8 C7 47 10 ?? ?? ?? ?? 90 C7 45 B0 C0 C6 2D 00 6A 04 8D 45 B0 50 6A 06 53 FF 55 D4} - condition: - uint16(0) == 0x5A4D and all of them -} -""" - -MAX_STRING_SIZE = 32 - - -def yara_scan(raw_data, rule_name): - yara_rules = yara.compile(source=rule_source) - matches = yara_rules.match(data=raw_data) - - for match in matches: - if match.rule != "Azorult": - continue - - for block in match.strings: - for instance in block.instances: - if block.identifier == rule_name: - return {block.identifier: instance.offset} - - -def string_from_offset(data, offset): - return data[offset : offset + MAX_STRING_SIZE].split(b"\0", 1)[0] - - -def extract_config(filebuf): - pe = pefile.PE(data=filebuf, fast_load=False) - image_base = pe.OPTIONAL_HEADER.ImageBase - - ref_c2 = yara_scan(filebuf, "$ref_c2") - if ref_c2 is None: - return - - ref_c2_offset = int(ref_c2["$ref_c2"]) - - c2_list_va = struct.unpack("i", filebuf[ref_c2_offset + 21 : ref_c2_offset + 25])[0] - c2_list_rva = c2_list_va - image_base - - try: - c2_list_offset = pe.get_offset_from_rva(c2_list_rva) - except pefile.PEFormatError as err: - print(err) - - c2_domain = string_from_offset(filebuf, c2_list_offset) - if c2_domain: - return {"address": c2_domain.decode()} - - return {} diff --git a/modules/processing/parsers/CAPE/BackOffLoader.py b/modules/processing/parsers/CAPE/BackOffLoader.py deleted file mode 100644 index f62fd29461d..00000000000 --- a/modules/processing/parsers/CAPE/BackOffLoader.py +++ /dev/null @@ -1,44 +0,0 @@ -from binascii import hexlify -from hashlib import md5 -from struct import unpack_from -from sys import argv - -import pefile -from Cryptodome.Cipher import ARC4 - -CFG_START = "1020304050607080" - - -def RC4(key, data): - cipher = ARC4.new(key) - return cipher.decrypt(data) - - -def extract_config(data): - config_data = {} - pe = pefile.PE(data=data) - for section in pe.sections: - if b".data" in section.Name: - data = section.get_data() - if CFG_START != hexlify(unpack_from(">8s", data, offset=8)[0]): - return None - rc4_seed = bytes(bytearray(unpack_from(">8B", data, offset=24))) - key = md5(rc4_seed).digest()[:5] - enc_data = bytes(bytearray(unpack_from(">8192B", data, offset=32))) - dec_data = RC4(key, enc_data) - config_data = { - "Version": unpack_from(">5s", data, offset=16)[0], - "RC4Seed": hexlify(rc4_seed), - "EncryptionKey": hexlify(key), - "OnDiskConfigKey": unpack_from("20s", data, offset=8224)[0], - "Build": dec_data[:16].strip("\x00"), - "URLs": [url.strip("\x00") for url in dec_data[16:].split("|")], - } - return config_data - - -if __name__ == "__main__": - filename = argv[1] - with open(filename, "r") as infile: - t = extract_config(infile.read()) - print(t) diff --git a/modules/processing/parsers/CAPE/BackOffPOS.py b/modules/processing/parsers/CAPE/BackOffPOS.py deleted file mode 100644 index c3bc9693af0..00000000000 --- a/modules/processing/parsers/CAPE/BackOffPOS.py +++ /dev/null @@ -1,45 +0,0 @@ -from binascii import hexlify -from hashlib import md5 -from struct import unpack_from -from sys import argv - -import pefile -from Cryptodome.Cipher import ARC4 - -header_ptrn = b"Content-Type: application/x-www-form-urlencoded" - - -def RC4(key, data): - cipher = ARC4.new(key) - return cipher.decrypt(data) - - -def extract_config(data): - config_data = {} - pe = pefile.PE(data=data) - for section in pe.sections: - if b".data" in section.Name: - data = section.get_data() - cfg_start = data.find(header_ptrn) - if not cfg_start or cfg_start == -1: - return None - start_offset = cfg_start + len(header_ptrn) + 1 - rc4_seed = bytes(bytearray(unpack_from(">8B", data, offset=start_offset))) - key = md5(rc4_seed).digest()[:5] - enc_data = bytes(bytearray(unpack_from(">8192B", data, offset=start_offset + 8))) - dec_data = RC4(key, enc_data) - config_data = { - "RC4Seed": hexlify(rc4_seed), - "EncryptionKey": hexlify(key), - "Build": dec_data[:16].strip("\x00"), - "URLs": [url.strip("\x00") for url in dec_data[16:].split("|")], - "Version": unpack_from(">5s", data, offset=start_offset + 16 + 8192)[0], - } - return config_data - - -if __name__ == "__main__": - filename = argv[1] - with open(filename, "rb") as infile: - t = extract_config(infile.read()) - print(t) diff --git a/modules/processing/parsers/CAPE/BitPaymer.py b/modules/processing/parsers/CAPE/BitPaymer.py deleted file mode 100644 index d8c5cfed09d..00000000000 --- a/modules/processing/parsers/CAPE/BitPaymer.py +++ /dev/null @@ -1,91 +0,0 @@ -# Copyright (C) 2019 Kevin O'Reilly (kevoreilly@gmail.com) -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU 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 General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -DESCRIPTION = "BitPaymer configuration parser." -AUTHOR = "kevoreilly" - -import string - -import pefile -import yara -from Cryptodome.Cipher import ARC4 - -rule_source = """ -rule BitPaymer -{ - meta: - author = "kevoreilly" - description = "BitPaymer Payload" - cape_type = "BitPaymer Payload" - - strings: - $decrypt32 = {6A 40 58 3B C8 0F 4D C1 39 46 04 7D 50 53 57 8B F8 81 E7 3F 00 00 80 79 05 4F 83 CF C0 47 F7 DF 99 1B FF 83 E2 3F 03 C2 F7 DF C1 F8 06 03 F8 C1 E7 06 57} - $antidefender = "TouchMeNot" wide - condition: - uint16(0) == 0x5A4D and all of them -} -""" - -LEN_BLOB_KEY = 40 - - -def convert_char(c): - if c in (string.letters + string.digits + string.punctuation + " \t\r\n"): - # ToDo gonna break as its int - return c - return f"\\x{ord(c):02x}" - - -def decrypt_rc4(key, data): - cipher = ARC4.new(key) - return cipher.decrypt(data) - - -def yara_scan(raw_data, rule_name): - yara_rules = yara.compile(source=rule_source) - matches = yara_rules.match(data=raw_data) - for match in matches: - if match.rule != "BitPaymer": - continue - - for block in match.strings: - for instance in block.instances: - if block.identifier == rule_name: - return {block.identifier: instance.offset} - - -def extract_rdata(pe): - for section in pe.sections: - if ".rdata" in section.Name: - return section.get_data(section.VirtualAddress, section.SizeOfRawData) - return None - - -def extract_config(file_data): - pe = pefile.PE(data=file_data, fast_load=False) - config = {} - blobs = filter(None, [x.strip(b"\x00\x00\x00\x00") for x in extract_rdata(pe).split(b"\x00\x00\x00\x00")]) - for blob in blobs: - if len(blob) < LEN_BLOB_KEY: - continue - raw = decrypt_rc4(blob[:LEN_BLOB_KEY][::-1], blob[LEN_BLOB_KEY:]) - if not raw: - continue - for item in raw.split(b"\x00"): - data = "".join(convert_char(c) for c in item) - if len(data) == 760: - config["RSA public key"] = data - elif len(data) > 1 and "\\x" not in data: - config["strings"] = data - return config diff --git a/modules/processing/parsers/CAPE/BlackDropper.py b/modules/processing/parsers/CAPE/BlackDropper.py deleted file mode 100644 index 31f57e7095e..00000000000 --- a/modules/processing/parsers/CAPE/BlackDropper.py +++ /dev/null @@ -1,96 +0,0 @@ -# Copyright (C) 2024 enzok -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU 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 General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - - -import datetime -import re -from contextlib import suppress - -import pefile - - -def get_current_year() -> str: - current_date = datetime.datetime.now() - return str(current_date.year) - - -def decrypt_string(encoded_string: str, key: str) -> str: - encoded_bytes = bytearray.fromhex(encoded_string) - key_bytes = bytearray(ord(char) for char in key) - encoded_length = len(encoded_bytes) - key_length = len(key_bytes) - decoded_bytes = bytearray(encoded_length) - - for i in range(encoded_length): - new_byte = (encoded_bytes[i] ^ key_bytes[i % key_length]) & 0xFF - decoded_bytes[i] = new_byte - - decoded_string = decoded_bytes.decode("ascii", errors="ignore") - - return decoded_string - - -def extract_config(data: bytes) -> dict: - pe = pefile.PE(data=data) - rdata_section = None - for section in pe.sections: - if b".rdata" in section.Name: - rdata_section = section - break - - if not rdata_section: - return {} - - rdata_data = rdata_section.get_data() - patterns = [b"Builder\.dll\x00", b"Builder\.exe\x00"] - matches = [] - for pattern in patterns: - matches.extend(re.finditer(pattern, rdata_data)) - - found_strings = set() - for match in matches: - start = max(0, match.start() - 1024) - end = min(len(rdata_data), match.end() + 1024) - found_strings.update(re.findall(b"[\x20-\x7E]{4,}?\x00", rdata_data[start:end])) - - result = {} - urls = [] - directories = [] - campaign = "" - - if found_strings: - for string in found_strings: - with suppress(UnicodeDecodeError): - decoded_string = string.decode("utf-8").rstrip("\x00") - - if re.match(r"^[0-9A-Fa-f]+$", decoded_string): - key = get_current_year() - url = decrypt_string(decoded_string, key) - if url: - urls.append(url) - elif decoded_string.count("\\") > 1: - directories.append(decoded_string) - elif re.match(r"^(?![A-Z]{6,}$)[a-zA-Z0-9\-=]{6,}$", decoded_string): - campaign = decoded_string - - result = {"urls": sorted(urls), "directories": directories, "campaign": campaign} - - return result - - -if __name__ == "__main__": - import sys - - with open(sys.argv[1], "rb") as f: - print(extract_config(f.read())) diff --git a/modules/processing/parsers/CAPE/BlackNix.py b/modules/processing/parsers/CAPE/BlackNix.py deleted file mode 100644 index 56dec06c9be..00000000000 --- a/modules/processing/parsers/CAPE/BlackNix.py +++ /dev/null @@ -1,57 +0,0 @@ -import pefile - - -def extract_raw_config(raw_data): - try: - pe = pefile.PE(data=raw_data) - rt_string_idx = [entry.id for entry in pe.DIRECTORY_ENTRY_RESOURCE.entries].index(pefile.RESOURCE_TYPE["RT_RCDATA"]) - rt_string_directory = pe.DIRECTORY_ENTRY_RESOURCE.entries[rt_string_idx] - for entry in rt_string_directory.directory.entries: - if str(entry.name) == "SETTINGS": - data_rva = entry.directory.entries[0].data.struct.OffsetToData - size = entry.directory.entries[0].data.struct.Size - data = pe.get_memory_mapped_image()[data_rva : data_rva + size] - return data.split("}") - except Exception: - return None - - -def decode(line): - return "".join(chr(ord(char) - 1) for char in line) - - -def domain_parse(config): - return [domain.split(":", 1)[0] for domain in config["Domains"].split(";")] - - -def extract_config(data): - try: - config_raw = extract_raw_config(data) - if config_raw: - return { - "Mutex": decode(config_raw[1])[::-1], - "Anti Sandboxie": decode(config_raw[2])[::-1], - "Max Folder Size": decode(config_raw[3])[::-1], - "Delay Time": decode(config_raw[4])[::-1], - "Password": decode(config_raw[5])[::-1], - "Kernel Mode Unhooking": decode(config_raw[6])[::-1], - "User More Unhooking": decode(config_raw[7])[::-1], - "Melt Server": decode(config_raw[8])[::-1], - "Offline Screen Capture": decode(config_raw[9])[::-1], - "Offline Keylogger": decode(config_raw[10])[::-1], - "Copy To ADS": decode(config_raw[11])[::-1], - "Domain": decode(config_raw[12])[::-1], - "Persistence Thread": decode(config_raw[13])[::-1], - "Active X Key": decode(config_raw[14])[::-1], - "Registry Key": decode(config_raw[15])[::-1], - "Active X Run": decode(config_raw[16])[::-1], - "Registry Run": decode(config_raw[17])[::-1], - "Safe Mode Startup": decode(config_raw[18])[::-1], - "Inject winlogon.exe": decode(config_raw[19])[::-1], - "Install Name": decode(config_raw[20])[::-1], - "Install Path": decode(config_raw[21])[::-1], - "Campaign Name": decode(config_raw[22])[::-1], - "Campaign Group": decode(config_raw[23])[::-1], - } - except Exception: - return None diff --git a/modules/processing/parsers/CAPE/Blister.py b/modules/processing/parsers/CAPE/Blister.py deleted file mode 100644 index 3207644ff9f..00000000000 --- a/modules/processing/parsers/CAPE/Blister.py +++ /dev/null @@ -1,557 +0,0 @@ -# BLISTER Configuration Extractor -# Python script to extract the configuration and payload from BLISTER samples. -# Author: soolidsnake (Elastic) -# https://elastic.github.io/security-research/tools/blister-config-extractor/ -# -# Modified for CAPE by kevoreilly - -import binascii -import json -import logging -import os -import sys -from optparse import OptionParser -from pathlib import Path -from struct import pack, unpack - -import pefile -import yara - -from lib.cuckoo.common.integrations.lznt1 import lznt1 - -log = logging.getLogger(__name__) - - -# https://github.com/Robin-Pwner/Rabbit-Cipher/ -def ROTL8(v, n): - return ((v << n) & 0xFF) | ((v >> (8 - n)) & 0xFF) - - -def ROTL16(v, n): - return ((v << n) & 0xFFFF) | ((v >> (16 - n)) & 0xFFFF) - - -def ROTL32(v, n): - return ((v << n) & 0xFFFFFFFF) | ((v >> (32 - n)) & 0xFFFFFFFF) - - -def ROTL64(v, n): - return ((v << n) & 0xFFFFFFFFFFFFFFFF) | ((v >> (64 - n)) & 0xFFFFFFFFFFFFFFFF) - - -def ROTR8(v, n): - return ROTL8(v, 8 - n) - - -def ROTR16(v, n): - return ROTL16(v, 16 - n) - - -def ROTR32(v, n): - return ROTL32(v, 32 - n) - - -def ROTR64(v, n): - return ROTL64(v, 64 - n) - - -def SWAP32(v): - return (ROTL32(v, 8) & 0x00FF00FF) | (ROTL32(v, 24) & 0xFF00FF00) - - -class Rabbit_state(object): - def __init__(self): - self.x = [0] * 8 - self.c = [0] * 8 - self.carry = 0 - - -class Rabbit_ctx(object): - def __init__(self): - self.m = Rabbit_state() - self.w = Rabbit_state() - - -class Rabbit(object): - def __init__(self, key, iv): - self.ctx = Rabbit_ctx() - self.set_iv(iv) - self.set_key(key) - if len(iv): - pass - - def g_func(self, x): - x = x & 0xFFFFFFFF - x = (x * x) & 0xFFFFFFFFFFFFFFFF - result = (x >> 32) ^ (x & 0xFFFFFFFF) - return result - - def set_key(self, key): - # generate four subkeys - key0 = unpack("> 16) & 0xFFFF) - s.x[3] = ((key0 << 16) & 0xFFFFFFFF) | ((key3 >> 16) & 0xFFFF) - s.x[5] = ((key1 << 16) & 0xFFFFFFFF) | ((key0 >> 16) & 0xFFFF) - s.x[7] = ((key2 << 16) & 0xFFFFFFFF) | ((key1 >> 16) & 0xFFFF) - # generate initial counter values - s.c[0] = ROTL32(key2, 16) - s.c[2] = ROTL32(key3, 16) - s.c[4] = ROTL32(key0, 16) - s.c[6] = ROTL32(key1, 16) - s.c[1] = (key0 & 0xFFFF0000) | (key1 & 0xFFFF) - s.c[3] = (key1 & 0xFFFF0000) | (key2 & 0xFFFF) - s.c[5] = (key2 & 0xFFFF0000) | (key3 & 0xFFFF) - s.c[7] = (key3 & 0xFFFF0000) | (key0 & 0xFFFF) - s.carry = 0 - - # Iterate system four times - for i in range(4): - self.next_state(self.ctx.m) - - for i in range(8): - # modify the counters - self.ctx.m.c[i] ^= self.ctx.m.x[(i + 4) & 7] - # Copy master instance to work instance - self.ctx.w = self.copy_state(self.ctx.m) - - def copy_state(self, state): - n = Rabbit_state() - n.carry = state.carry - - for i, j in enumerate(state.x): - n.x[i] = j - for i, j in enumerate(state.c): - n.c[i] = j - return n - - def set_iv(self, iv): - # generate four subvectors - v = [0] * 4 - v[0] = unpack("> 16) | (v[2] & 0xFFFF0000) - v[3] = ((v[2] << 16) | (v[0] & 0x0000FFFF)) & 0xFFFFFFFF - # Modify work's counter values - for i in range(8): - self.ctx.w.c[i] = self.ctx.m.c[i] ^ v[i & 3] - # Copy state variables but not carry flag - tmp = [] - - for cc in self.ctx.m.x: - tmp += [cc] - self.ctx.w.x = tmp - - # Iterate system four times - for i in range(4): - self.next_state(self.ctx.w) - - def next_state(self, state): - g = [0] * 8 - x = [0x4D34D34D, 0xD34D34D3, 0x34D34D34] - # calculate new counter values - for i in range(8): - tmp = state.c[i] - state.c[i] = (state.c[i] + x[i % 3] + state.carry) & 0xFFFFFFFF - state.carry = state.c[i] < tmp - # calculate the g-values - for i in range(8): - g[i] = self.g_func(state.x[i] + state.c[i]) - # calculate new state values - - j = 7 - i = 0 - while i < 8: - state.x[i] = (g[i] + ROTL32(g[j], 16) + ROTL32(g[j - 1], 16)) & 0xFFFFFFFF - i += 1 - j += 1 - state.x[i] = (g[i] + ROTL32(g[j & 7], 8) + g[j - 1]) & 0xFFFFFFFF - i += 1 - j += 1 - j &= 7 - - def crypt(self, msg): - plain = [] - msg_len = len(msg) - c = self.ctx - x = [0] * 4 - start = 0 - while True: - self.next_state(c.w) - for i in range(4): - x[i] = c.w.x[i << 1] - x[0] ^= (c.w.x[5] >> 16) ^ (c.w.x[3] << 16) - x[1] ^= (c.w.x[7] >> 16) ^ (c.w.x[5] << 16) - x[2] ^= (c.w.x[1] >> 16) ^ (c.w.x[7] << 16) - x[3] ^= (c.w.x[3] >> 16) ^ (c.w.x[1] << 16) - b = [0] * 16 - for i, j in enumerate(x): - for z in range(4): - b[z + 4 * i] = 0xFF & (j >> (8 * z)) - for i in range(16): - plain.append((msg[start] ^ b[i])) - start += 1 - if start == msg_len: - return bytes(plain) - - -def st(b): - a = "" - for x in b: - a += chr(x) - return a - - -def p32(a): - return pack(". - -from contextlib import suppress - -import pefile - -DESCRIPTION = "BuerLoader configuration parser." -AUTHOR = "kevoreilly" - - -def decrypt_string(string): - return "".join(chr(ord(char) - 6) for char in string) - - -def extract_config(filebuf): - cfg = {} - pe = pefile.PE(data=filebuf) - data_sections = [s for s in pe.sections if s.Name.find(b".data") != -1] - if not data_sections: - return None - data = data_sections[0].get_data() - for item in data.split(b"\x00\x00"): - with suppress(Exception): - dec = decrypt_string(item.lstrip(b"\x00").rstrip(b"\x00").decode()) - if "dll" not in dec and " " not in dec and ";" not in dec and "." in dec: - cfg.setdefault("address", []).append(dec) - return cfg diff --git a/modules/processing/parsers/CAPE/BumbleBee.py b/modules/processing/parsers/CAPE/BumbleBee.py deleted file mode 100644 index b53fdfc722f..00000000000 --- a/modules/processing/parsers/CAPE/BumbleBee.py +++ /dev/null @@ -1,242 +0,0 @@ -# Thanks to @MuziSec - https://github.com/MuziSec/malware_scripts/blob/main/bumblebee/extract_config.py -# 2024 updates by @enzok -# -import logging -import traceback -from contextlib import suppress - -import pefile -import regex as re -import yara -from Cryptodome.Cipher import ARC4 - -log = logging.getLogger(__name__) -log.setLevel(logging.INFO) - -rule_source = """ -rule BumbleBee -{ - meta: - author = "enzok" - description = "BumbleBee 2024" - strings: - $rc4key = {48 [6] 48 [6] E8 [4] 4C 89 AD [4] 4C 89 AD [4] 4C 89 B5 [4] 4C 89 AD [4] 44 88 AD [4] 48 8D 15 [4] 44 38 2D [4] 75} - $botidlgt = {4C 8B C1 B? 4F 00 00 00 48 8D 0D [4] E8 [4] 4C 8B C3 48 8D 0D [4] B? 4F 00 00 00 E8 [4] 4C 8B C3 48 8D 0D [4] B? FF 0F 00 00 E8} - $botid = {90 48 [6] E8 [4] 4C 89 AD [4] 4C 89 AD [4] 4C 89 B5 [4] 4C 89 AD [4] 44 88 AD [4] 48 8D 15 [4] 44 38 2D [4] 75} - $port = {4C 89 6D ?? 4C 89 6D ?? 4c 89 75 ?? 4C 89 6D ?? 44 88 6D ?? 48 8D 05 [4] 44 38 2D [4] 75} - $dga1 = {4C 89 75 ?? 4C 89 6D ?? 44 88 6D ?? 48 8B 1D [4] 48 8D 0D [4] E8 [4] 8B F8} - $dga2 = {48 8D 0D [4] E8 [4] 8B F0 4C 89 6D ?? 4C 89 6D ?? 4C 89 75 ?? 4C 89 6D ?? 44 88 6D ?? 48 8D 15 [4] 44 38 2D [4] 75} - condition: - $rc4key and all of ($botid*) and 2 of ($port, $port, $dga1, $dga2) -} -""" - -yara_rules = yara.compile(source=rule_source) - - -def extract_key_data(data, pe, key_match): - """ - Given key match, convert rva to file offset and return key data at that offset. - """ - try: - # Get relative rva. The LEA is using a relative address. This address is relative to the address of the next ins. - relative_rva = pe.get_rva_from_offset(key_match.start() + int(len(key_match.group()) / 2)) - # Now that we have the relative rva, we need to get the file offset - key_offset = pe.get_offset_from_rva(relative_rva + int.from_bytes(key_match.group("key"), byteorder="little")) - # Read arbitrary number of byes from key offset and split on null bytes to extract key - key = data[key_offset : key_offset + 0x40].split(b"\x00")[0] - except Exception as e: - log.debug(f"There was an exception extracting the key: {e}") - log.debug(traceback.format_exc()) - return False - return key - - -def extract_config_data(data, pe, config_match): - """ - Given config match, convert rva to file offset and return data at that offset. - The LEA ins are using relative addressing. Referenced data is relative to the address of the NEXT ins. - This is inefficient but I'm bad at Python, okay? - """ - try: - # Get campaign id ciphertext - campaign_id_rva = pe.get_rva_from_offset(config_match.start() + int(len(config_match.group("campaign_id_ins")))) - campaign_id_offset = pe.get_offset_from_rva( - campaign_id_rva + int.from_bytes(config_match.group("campaign_id"), byteorder="little") - ) - campaign_id_ct = data[campaign_id_offset : campaign_id_offset + 0x10] - except Exception as e: - log.debug(f"There was an exception extracting the campaign id: {e}") - log.debug(traceback.format_exc()) - return False, False, False - - try: - # Get botnet id ciphertext - botnet_id_rva = pe.get_rva_from_offset( - config_match.start() + int(len(config_match.group("campaign_id_ins"))) + int(len(config_match.group("botnet_id_ins"))) - ) - botnet_id_offset = pe.get_offset_from_rva( - botnet_id_rva + int.from_bytes(config_match.group("botnet_id"), byteorder="little") - ) - botnet_id_ct = data[botnet_id_offset : botnet_id_offset + 0x10] - except Exception as e: - log.debug(f"There was an exception extracting the botnet id: {e}") - log.debug(traceback.format_exc()) - return False, False, False - - # Get C2 ciphertext - try: - c2s_rva = pe.get_rva_from_offset( - config_match.start() - + int(len(config_match.group("campaign_id_ins"))) - + int(len(config_match.group("botnet_id_ins"))) - + int(len(config_match.group("c2s_ins"))) - ) - c2s_offset = pe.get_offset_from_rva(c2s_rva + int.from_bytes(config_match.group("c2s"), byteorder="little")) - c2s_ct = data[c2s_offset : c2s_offset + 0x400] - except Exception as e: - log.debug(f"There was an exception extracting the C2s: {e}") - log.debug(traceback.format_exc()) - return False, False, False - - return campaign_id_ct, botnet_id_ct, c2s_ct - - -def extract_2024(pe, filebuf): - cfg = {} - rc4key_init_offset = 0 - botid_init_offset = 0 - port_init_offset = 0 - dga1_init_offset = 0 - dga2_init_offset = 0 - botidlgt_init_offset = 0 - - matches = yara_rules.match(data=filebuf) - if not matches: - return - - for match in matches: - if match.rule != "BumbleBee": - continue - for item in match.strings: - for instance in item.instances: - if "$rc4key" in item.identifier: - rc4key_init_offset = int(instance.offset) - elif "$botidlgt" in item.identifier: - botidlgt_init_offset = int(instance.offset) - elif "$botid" in item.identifier: - botid_init_offset = int(instance.offset) - elif "$port" in item.identifier: - port_init_offset = int(instance.offset) - elif "$dga1" in item.identifier: - dga1_init_offset = int(instance.offset) - elif "$dga2" in item.identifier: - dga2_init_offset = int(instance.offset) - - if not rc4key_init_offset: - return - - key_offset = pe.get_dword_from_offset(rc4key_init_offset + 57) - key_rva = pe.get_rva_from_offset(rc4key_init_offset + 61) + key_offset - key = pe.get_string_at_rva(key_rva) - cfg["RC4 key"] = key.decode() - - botid_offset = pe.get_dword_from_offset(botid_init_offset + 51) - botid_rva = pe.get_rva_from_offset(botid_init_offset + 55) + botid_offset - botid_len_offset = pe.get_dword_from_offset(botidlgt_init_offset + 31) - botid_data = pe.get_data(botid_rva)[:botid_len_offset] - with suppress(Exception): - botid = ARC4.new(key).decrypt(botid_data).split(b"\x00")[0].decode() - cfg["Botid"] = botid - - port_offset = pe.get_dword_from_offset(port_init_offset + 23) - port_rva = pe.get_rva_from_offset(port_init_offset + 27) + port_offset - port_len_offset = pe.get_dword_from_offset(botidlgt_init_offset + 4) - port_data = pe.get_data(port_rva)[:port_len_offset] - with suppress(Exception): - port = ARC4.new(key).decrypt(port_data).split(b"\x00")[0].decode() - cfg["Port"] = port - - dgaseed_offset = pe.get_dword_from_offset(dga1_init_offset + 15) - dgaseed_rva = pe.get_rva_from_offset(dga1_init_offset + 19) + dgaseed_offset - dgaseed_data = pe.get_qword_at_rva(dgaseed_rva) - cfg["DGA seed"] = int(dgaseed_data) - - numdga_offset = pe.get_dword_from_offset(dga1_init_offset + 22) - numdga_rva = pe.get_rva_from_offset(dga1_init_offset + 26) + numdga_offset - numdga_data = pe.get_string_at_rva(numdga_rva) - cfg["Number DGA domains"] = numdga_data.decode() - - domainlen_offset = pe.get_dword_from_offset(dga2_init_offset + 3) - domainlen_rva = pe.get_rva_from_offset(dga2_init_offset + 7) + domainlen_offset - domainlen_data = pe.get_string_at_rva(domainlen_rva) - cfg["Domain length"] = domainlen_data.decode() - - tld_offset = pe.get_dword_from_offset(dga2_init_offset + 37) - tld_rva = pe.get_rva_from_offset(dga2_init_offset + 41) + tld_offset - tld_data = pe.get_string_at_rva(tld_rva).decode() - cfg["TLD"] = tld_data - - return cfg - - -def extract_config(data): - """ - Extract key and config and decrypt - """ - cfg = {} - pe = None - try: - with suppress(Exception): - pe = pefile.PE(data=data, fast_load=True) - - if not pe: - return cfg - - key_regex = re.compile(rb"(\x48\x8D.(?P....)\x80\x3D....\x00)", re.DOTALL) - regex = re.compile( - rb"(?\x48\x8D.(?P....))(?P\x48\x8D.(?P....))(?P\x48\x8D.(?P....))", - re.DOTALL, - ) - # Extract Key - key_match = list(key_regex.finditer(data)) - if len(key_match) > 1: - for index, match in enumerate(key_match): - key = extract_key_data(data, pe, match) - if not key: - continue - if index == 0: - cfg["Botnet ID"] = key.decode() - elif index == 1: - cfg["Campaign ID"] = key.decode() - elif index == 2: - cfg["Data"] = key.decode("latin-1") - elif index == 3: - cfg["C2s"] = list(key.decode().split(",")) - elif len(key_match) == 1: - key = extract_key_data(data, pe, key_match[0]) - if not key: - return cfg - cfg["RC4 Key"] = key.decode() - # Extract config ciphertext - config_match = regex.search(data) - campaign_id, botnet_id, c2s = extract_config_data(data, pe, config_match) - if campaign_id: - cfg["Campaign ID"] = ARC4.new(key).decrypt(campaign_id).split(b"\x00")[0].decode() - if botnet_id: - cfg["Botnet ID"] = ARC4.new(key).decrypt(botnet_id).split(b"\x00")[0].decode() - if c2s: - cfg["C2s"] = list(ARC4.new(key).decrypt(c2s).split(b"\x00")[0].decode().split(",")) - except Exception as e: - log.error("This is broken: %s", str(e), exc_info=True) - - if not cfg: - cfg = extract_2024(pe, data) - - return cfg - - -if __name__ == "__main__": - import sys - - print(extract_config(open(sys.argv[1], "rb").read())) diff --git a/modules/processing/parsers/CAPE/Carbanak.py b/modules/processing/parsers/CAPE/Carbanak.py deleted file mode 100644 index b3d2cb2e086..00000000000 --- a/modules/processing/parsers/CAPE/Carbanak.py +++ /dev/null @@ -1,186 +0,0 @@ -# Copyright (C) 2024 enzok -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU 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 General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - - -import logging -import re -from contextlib import suppress - -import pefile -import yara - -log = logging.getLogger(__name__) -log.setLevel(logging.INFO) - -rule_source = """ -rule Carbanak -{ - meta: - author = "enzok" - description = "Carbanak sbox constants" - cape_type = "Carbanak Payload" - strings: - $constants = {0F B7 05 [3] 00 0F B7 1D [3] 00 83 25 [3] 00 00 89 05 [3] 00 0F B7 05 [3] 00 89 1D [3] 00 89 05 [3] 00 33 C0 4? 8D 4D} - condition: - all of them -} -""" - -yara_rules = yara.compile(source=rule_source) - -const_a = 0 -const_b = 0 -const_c = 0 - - -def decode_string(src, sbox): - lenstr = len(src) - 4 - if lenstr < 0: - lenstr = 0 - newstr = bytearray() - lenblock = int(lenstr / 4) - nb = 0 - rb = 0 - delta = 0 - n = 0 - i = 0 - while n < lenstr: - if rb == 0: - nb += 1 - if nb <= 4: - delta = src[i] - 97 - i += 1 - rb = lenblock - else: - rb = lenstr - n - elif rb > 0: - rb -= 1 - c = src[i] - if c < 32: - min = 1 - max = 31 - elif c < 128: - min = 32 - max = 127 - else: - min = 128 - max = 255 - c = sbox[c] - c -= delta - if c < min: - c = max - min + c - n += 1 - newstr.append(c) - i += 1 - return newstr - - -def scramble(sbox, start, end, count): - global const_a - length = end - start + 1 - while count > 0: - s1 = (const_c + const_a * const_b) & 0xFFFF - const_a = (const_c + s1 * const_b) & 0xFFFF - i = start + s1 % length - s3 = sbox[i] - j = start + const_a % length - sbox[i] = sbox[j] - sbox[j] = s3 - count -= 1 - return sbox - - -def extract_config(filebuf): - global const_a, const_b, const_c - cfg = {} - constants_offset = None - pe = pefile.PE(data=filebuf) - matches = yara_rules.match(data=filebuf) - if not matches: - return - - for match in matches: - if match.rule != "Carbanak": - continue - for item in match.strings: - for instance in item.instances: - if "$constants" in item.identifier: - constants_offset = int(instance.offset) - - if not constants_offset: - return - - data_sections = [s for s in pe.sections if s.Name.find(b".data") != -1] - text_sections = [s for s in pe.sections if s.Name.find(b".text") != -1] - - if not data_sections or not text_sections: - return None - - text_start = text_sections[0].PointerToRawData - rva = constants_offset - text_start + text_sections[0].VirtualAddress - const_b_offset = pe.get_dword_from_offset(constants_offset + 3) - const_b_rva = rva + const_b_offset + 7 - const_b_offset = const_b_rva - data_sections[0].VirtualAddress + data_sections[0].PointerToRawData - const_b = pe.get_word_from_offset(const_b_offset) - const_a = pe.get_word_from_offset(const_b_offset - 2) - const_c = pe.get_word_from_offset(const_b_offset + 2) - - # init sbox - sbox_init = bytearray(range(256)) - count = const_a % 1000 + 128 - sbox_init = scramble(sbox_init, 1, 31, count) - sbox_init = scramble(sbox_init, 32, 127, count) - sbox_init = scramble(sbox_init, 128, 255, count) - sbox = bytearray(256) - for idx, dst in enumerate(sbox_init): - sbox[dst] = idx - - rdata_sections = [s for s in pe.sections if s.Name.find(b".rdata") != -1] - if rdata_sections: - rdata = rdata_sections[0].get_data() - items = rdata.split(b"\x00") - items = [item for item in items if item != b""] - for item in items: - with suppress(IndexError, UnicodeDecodeError, ValueError): - dec = decode_string(item, sbox).decode("utf8") - if dec: - ver = re.findall("^(\d+\.\d+)$", dec) - if ver: - cfg["Version"] = ver[0] - - data = data_sections[0].get_data() - items = data.split(b"\x00") - - with suppress(IndexError, UnicodeDecodeError, ValueError): - cfg["Unknown 1"] = decode_string(items[0], sbox).decode("utf8") - cfg["Unknown 2"] = decode_string(items[8], sbox).decode("utf8") - c2_dec = decode_string(items[10], sbox).decode("utf8") - if "|" in c2_dec: - c2_dec = c2_dec.split("|") - cfg["C2"] = c2_dec - if float(cfg["Version"]) < 1.7: - cfg["Campaign Id"] = decode_string(items[276], sbox).decode("utf8") - else: - cfg["Campaign Id"] = decode_string(items[25], sbox).decode("utf8") - - return cfg - - -if __name__ == "__main__": - import sys - from pathlib import Path - - log.setLevel(logging.DEBUG) - data = Path(sys.argv[1]).read_bytes() - print(extract_config(data)) diff --git a/modules/processing/parsers/CAPE/ChChes.py b/modules/processing/parsers/CAPE/ChChes.py deleted file mode 100644 index e001f599743..00000000000 --- a/modules/processing/parsers/CAPE/ChChes.py +++ /dev/null @@ -1,75 +0,0 @@ -# Copyright (C) 2015 Kevin O'Reilly kevin.oreilly@contextis.co.uk -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU 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 General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -DESCRIPTION = "ChChes configuration parser." -AUTHOR = "kevoreilly" - -import yara - -rule_source = """ -rule ChChes -{ - meta: - author = "kev" - description = "ChChes Payload" - cape_type = "ChChes Payload" - strings: - $payload1 = {55 8B EC 53 E8 EB FC FF FF E8 DB FF FF FF 05 10 FE 2A 00 33 DB 39 58 44 75 58 56 57 50 E8 57 00 00 00 59 8B F0 E8 AB FF FF FF B9 01 1F 2A 00 BF D0 1C 2A 00 2B CF 03 C1 39 5E 30 76 0F} - $payload2 = {55 8B EC 53 E8 8F FB FF FF E8 DB FF FF FF 05 00 07 FF 00 33 DB 39 58 44 75 58 56 57 50 E8 57 00 00 00 59 8B F0 E8 AB FF FF FF B9 5D 20 FE 00 BF D0 1C FE 00 2B CF 03 C1 39 5E 30 76 0F } - $payload3 = {55 8B EC 53 E8 E6 FC FF FF E8 DA FF FF FF 05 80 FC FC 00 33 DB 39 58 44 75 58 56 57 50 E8 57 00 00 00 59 8B F0 E8 AA FF FF FF B9 05 1F FC 00 BF D0 1C FC 00 2B CF 03 C1 39 5E 30 76 0F} - $payload4 = {55 8B EC E8 ?? ?? FF FF E8 D? FF FF FF 05 ?? ?? ?? 00 83 78 44 00 75 40 56 57 50 E8 3E 00 00 00 59 8B F0 6A 00 FF 76 30 E8 A8 FF FF FF B9 ?? ?? ?? 00 BF 00 1A E1 00 2B CF 03 C1 50 FF 56 70} - condition: - $payload1 or $payload2 or $payload3 or $payload4 -} -""" - -MAX_STRING_SIZE = 128 - - -def yara_scan(raw_data): - addresses = {} - yara_rules = yara.compile(source=rule_source) - matches = yara_rules.match(data=raw_data) - for match in matches: - if match.rule != "ChChes": - continue - - for block in match.strings: - for instance in block.instances: - addresses[block.identifier] = instance.offset - return addresses - - -def string_from_offset(data, offset): - return data[offset : offset + MAX_STRING_SIZE].split(b"\0", 1)[0] - - -def extract_config(filebuf): - tmp_config = {} - yara_matches = yara_scan(filebuf) - - c2_offsets = [] - if yara_matches.get("$payload1"): - c2_offsets.append(0xE455) - if yara_matches.get("$payload2"): - c2_offsets.append(0xED55) - if yara_matches.get("$payload3"): - c2_offsets.append(0xE2B9) - # no c2 for type4 - - for c2_offset in c2_offsets: - c2_url = string_from_offset(filebuf, c2_offset) - if c2_url: - tmp_config.setdefault("c2_url", []).append(c2_url) - - return tmp_config diff --git a/modules/processing/parsers/CAPE/CobaltStrikeBeacon.py b/modules/processing/parsers/CAPE/CobaltStrikeBeacon.py deleted file mode 100644 index 0201c0f4277..00000000000 --- a/modules/processing/parsers/CAPE/CobaltStrikeBeacon.py +++ /dev/null @@ -1,463 +0,0 @@ -""" -Parses CobaltStrike Beacon's configuration from PE file or memory dump. -By Gal Kristal from SentinelOne (gkristal.w@gmail.com) - -Inspired by https://github.com/JPCERTCC/aa-tools/blob/master/cobaltstrikescan.py - -TODO: - 1. Parse headers modifiers - 2. Dynamic size parsing -""" - -import argparse -import io -import json -import logging -import re -from base64 import b64encode -from collections import OrderedDict -from pathlib import Path -from socket import inet_ntoa -from struct import unpack - -import pefile - -try: - from netstruct import unpack as netunpack - - HAVE_NETSTRUCT = True -except ImportError: - HAVE_NETSTRUCT = False - -log = logging.getLogger(__name__) - -COLUMN_WIDTH = 35 -SUPPORTED_VERSIONS = (3, 4) - - -class Base64Encoder(json.JSONEncoder): - def default(self, o): - if isinstance(o, bytes): - return b64encode(o).decode() - return json.JSONEncoder.default(self, o) - - -class confConsts: - MAX_SETTINGS = 64 - TYPE_NONE = 0 - TYPE_SHORT = 1 - TYPE_INT = 2 - TYPE_STR = 3 - - START_PATTERNS = { - 3: b"\x69\x68\x69\x68\x69\x6b..\x69\x6b\x69\x68\x69\x6b..\x69\x6a", - 4: b"\x2e\x2f\x2e\x2f\x2e\x2c..\x2e\x2c\x2e\x2f\x2e\x2c..\x2e", - } - START_PATTERN_DECODED = b"\x00\x01\x00\x01\x00\x02..\x00\x02\x00\x01\x00\x02..\x00" - CONFIG_SIZE = 4096 - XORBYTES = {3: 0x69, 4: 0x2E} - - -def read_dword_be(fh): - data = fh.read(4) - if not data or len(data) != 4: - return None - return unpack(">I", data)[0] - - -class packedSetting: - def __init__( - self, - pos, - datatype, - length=0, - isBlob=False, - isHeaders=False, - isIpAddress=False, - isBool=False, - isDate=False, - boolFalseValue=0, - isProcInjectTransform=False, - isMalleableStream=False, - enum=None, - mask=None, - ): - self.pos = pos - self.datatype = datatype - self.is_blob = isBlob - self.is_headers = isHeaders - self.is_ipaddress = isIpAddress - self.is_bool = isBool - self.is_date = isDate - self.is_malleable_stream = isMalleableStream - self.bool_false_value = boolFalseValue - self.is_transform = isProcInjectTransform - self.enum = enum - self.mask = mask - if datatype == confConsts.TYPE_STR and length == 0: - raise (Exception("if datatype is TYPE_STR then length must not be 0")) - - if datatype == confConsts.TYPE_SHORT: - self.length = 2 - elif datatype == confConsts.TYPE_INT: - self.length = 4 - else: - self.length = length - - def binary_repr(self): - """ - Param number - Type - Length - Value - """ - self_repr = bytearray(6) - self_repr[1] = self.pos - self_repr[3] = self.datatype - self_repr[4:6] = self.length.to_bytes(2, "big") - return self_repr - - def pretty_repr(self, full_config_data): - data_offset = full_config_data.find(self.binary_repr()) - if data_offset < 0: - return "Not Found" - - repr_len = len(self.binary_repr()) - conf_data = full_config_data[data_offset + repr_len : data_offset + repr_len + self.length] - if self.datatype == confConsts.TYPE_SHORT: - conf_data = unpack(">H", conf_data)[0] - if conf_data is None: - return - if self.is_bool: - return str(conf_data != self.bool_false_value) - elif self.enum: - return self.enum[conf_data] - elif self.mask: - ret_arr = [] - for k, v in self.mask.items(): - if k == 0 == conf_data: - ret_arr.append(v) - if k & conf_data: - ret_arr.append(v) - return ret_arr - else: - return conf_data - - elif self.datatype == confConsts.TYPE_INT: - if self.is_ipaddress: - return inet_ntoa(conf_data) - - conf_data = unpack(">I", conf_data)[0] - if self.is_date and conf_data != 0: - fulldate = str(conf_data) - return f"{fulldate[:4]}-{fulldate[4:6]}-{fulldate[6:]}" - - return conf_data - - elif self.is_blob: - if self.enum is not None: - ret_arr = [] - i = 0 - while i < len(conf_data): - v = conf_data[i] - if v == 0: - return ret_arr - v = self.enum[v] - if v: - ret_arr.append(v) - i += 1 - - # Only EXECUTE_TYPE for now - else: - if HAVE_NETSTRUCT: - # Skipping unknown short value in the start - string1 = netunpack(b"I$", conf_data[i + 3 :])[0].decode() - string2 = netunpack(b"I$", conf_data[i + 3 + 4 + len(string1) :])[0].decode() - ret_arr.append("{}:{}".format(string1.strip("\x00"), string2.strip("\x00"))) - i += len(string1) + len(string2) + 11 - - elif self.is_transform: - if conf_data == bytes(len(conf_data)): - return "Empty" - - prepend_length = unpack(">I", conf_data[:4])[0] - prepend = conf_data[4 : 4 + prepend_length].hex() - append_length_offset = prepend_length + 4 - append_length = unpack(">I", conf_data[append_length_offset : append_length_offset + 4])[0] - append = conf_data[append_length_offset + 4 : append_length_offset + 4 + append_length].hex() - ret_arr = [ - prepend, - append if append_length < 256 and append != bytes(append_length) else "Empty", - ] - - return ret_arr - - elif self.is_malleable_stream: - prog = [] - with io.BytesIO(conf_data) as fh: - op = read_dword_be(fh) - while op: - if op == 1: - bytes_len = read_dword_be(fh) - prog.append(f"Remove {bytes_len} bytes from the end") - elif op == 2: - bytes_len = read_dword_be(fh) - prog.append(f"Remove {bytes_len} bytes from the beginning") - elif op == 3: - prog.append("Base64 decode") - elif op == 8: - prog.append("NetBIOS decode 'a'") - elif op == 11: - prog.append("NetBIOS decode 'A'") - elif op == 13: - prog.append("Base64 URL-safe decode") - elif op == 15: - prog.append("XOR mask w/ random key") - op = read_dword_be(fh) - conf_data = prog - else: - conf_data = conf_data.hex() - - return conf_data - - elif self.is_headers: - conf_data = conf_data.strip(b"\x00") - conf_data = [chunk[1:].decode() for chunk in conf_data.split(b"\x00") if len(chunk) > 1] - return conf_data - - conf_data = conf_data.strip(b"\x00").decode() - return conf_data - - -class BeaconSettings: - BEACON_TYPE = {0x0: "HTTP", 0x1: "Hybrid HTTP DNS", 0x2: "SMB", 0x4: "TCP", 0x8: "HTTPS", 0x10: "Bind TCP"} - ACCESS_TYPE = {0x1: "Use direct connection", 0x2: "Use IE settings", 0x4: "Use proxy server"} - EXECUTE_TYPE = { - 0x1: "CreateThread", - 0x2: "SetThreadContext", - 0x3: "CreateRemoteThread", - 0x4: "RtlCreateUserThread", - 0x5: "NtQueueApcThread", - 0x6: None, - 0x7: None, - 0x8: "NtQueueApcThread-s", - } - # TRANSFORMSTEP = {1: "append", 2: "prepend", 3: "base64", 4: "print", 5: "parameter", 6: "header", 7: "build", 8: "netbios", 9: "_parameter", 10: "_header", - # 11: "netbiosu", 12: "uri_append", 13: "base64_url", 14: "strrep", 15: "mask"} - ALLOCATION_FUNCTIONS = {0: "VirtualAllocEx", 1: "NtMapViewOfSection"} - - def __init__(self, version): - if version not in SUPPORTED_VERSIONS: - log.debug("Error: Only supports version 3 and 4, not %d", version) - self.version = version - self.settings = OrderedDict() - self.init() - - def init(self): - self.settings["BeaconType"] = packedSetting(1, confConsts.TYPE_SHORT, mask=self.BEACON_TYPE) - self.settings["Port"] = packedSetting(2, confConsts.TYPE_SHORT) - self.settings["SleepTime"] = packedSetting(3, confConsts.TYPE_INT) - self.settings["MaxGetSize"] = packedSetting(4, confConsts.TYPE_INT) - self.settings["Jitter"] = packedSetting(5, confConsts.TYPE_SHORT) - self.settings["MaxDNS"] = packedSetting(6, confConsts.TYPE_SHORT) - # Silencing for now - self.settings["PublicKey"] = packedSetting(7, confConsts.TYPE_STR, 256, isBlob=True) - self.settings["C2Server"] = packedSetting(8, confConsts.TYPE_STR, 256) - self.settings["UserAgent"] = packedSetting(9, confConsts.TYPE_STR, 128) - self.settings["HttpPostUri"] = packedSetting(10, confConsts.TYPE_STR, 64) - - # ref: https://www.cobaltstrike.com/help-malleable-c2 | https://usualsuspect.re/article/cobalt-strikes-malleable-c2-under-the-hood - self.settings["Malleable_C2_Instructions"] = packedSetting( - 11, confConsts.TYPE_STR, 256, isBlob=True, isMalleableStream=True - ) - self.settings["HttpGet_Metadata"] = packedSetting(12, confConsts.TYPE_STR, 256, isHeaders=True) - self.settings["HttpPost_Metadata"] = packedSetting(13, confConsts.TYPE_STR, 256, isHeaders=True) - self.settings["SpawnTo"] = packedSetting(14, confConsts.TYPE_STR, 16, isBlob=True) - self.settings["PipeName"] = packedSetting(15, confConsts.TYPE_STR, 128) - # Options 16-18 are deprecated in 3.4 - self.settings["DNS_Idle"] = packedSetting(19, confConsts.TYPE_INT, isIpAddress=True) - self.settings["DNS_Sleep"] = packedSetting(20, confConsts.TYPE_INT) - # Options 21-25 are for SSHAgent - self.settings["SSH_Host"] = packedSetting(21, confConsts.TYPE_STR, 256) - self.settings["SSH_Port"] = packedSetting(22, confConsts.TYPE_SHORT) - self.settings["SSH_Username"] = packedSetting(23, confConsts.TYPE_STR, 128) - self.settings["SSH_Password_Plaintext"] = packedSetting(24, confConsts.TYPE_STR, 128) - self.settings["SSH_Password_Pubkey"] = packedSetting(25, confConsts.TYPE_STR, 6144) - - self.settings["HttpGet_Verb"] = packedSetting(26, confConsts.TYPE_STR, 16) - self.settings["HttpPost_Verb"] = packedSetting(27, confConsts.TYPE_STR, 16) - self.settings["HttpPostChunk"] = packedSetting(28, confConsts.TYPE_INT) - self.settings["Spawnto_x86"] = packedSetting(29, confConsts.TYPE_STR, 64) - self.settings["Spawnto_x64"] = packedSetting(30, confConsts.TYPE_STR, 64) - self.settings["CryptoScheme"] = packedSetting(31, confConsts.TYPE_SHORT) - self.settings["Proxy_Config"] = packedSetting(32, confConsts.TYPE_STR, 128) - self.settings["Proxy_User"] = packedSetting(33, confConsts.TYPE_STR, 64) - self.settings["Proxy_Password"] = packedSetting(34, confConsts.TYPE_STR, 64) - self.settings["Proxy_Behavior"] = packedSetting(35, confConsts.TYPE_SHORT, enum=self.ACCESS_TYPE) - # Option 36 is deprecated - self.settings["Watermark"] = packedSetting(37, confConsts.TYPE_INT) - self.settings["bStageCleanup"] = packedSetting(38, confConsts.TYPE_SHORT, isBool=True) - self.settings["bCFGCaution"] = packedSetting(39, confConsts.TYPE_SHORT, isBool=True) - self.settings["KillDate"] = packedSetting(40, confConsts.TYPE_INT, isDate=True) - # Inner parameter, does not seem interesting so silencing - # self.settings["textSectionEnd (0 if !sleep_mask)"] = packedSetting(41, confConsts.TYPE_INT) - - # TODO: dynamic size parsing - # self.settings["ObfuscateSectionsInfo"] = packedSetting(42, confConsts.TYPE_STR, %d, isBlob=True) - self.settings["bProcInject_StartRWX"] = packedSetting(43, confConsts.TYPE_SHORT, isBool=True, boolFalseValue=4) - self.settings["bProcInject_UseRWX"] = packedSetting(44, confConsts.TYPE_SHORT, isBool=True, boolFalseValue=32) - self.settings["bProcInject_MinAllocSize"] = packedSetting(45, confConsts.TYPE_INT) - self.settings["ProcInject_PrependAppend_x86"] = packedSetting( - 46, confConsts.TYPE_STR, 256, isBlob=True, isProcInjectTransform=True - ) - self.settings["ProcInject_PrependAppend_x64"] = packedSetting( - 47, confConsts.TYPE_STR, 256, isBlob=True, isProcInjectTransform=True - ) - self.settings["ProcInject_Execute"] = packedSetting(51, confConsts.TYPE_STR, 128, isBlob=True, enum=self.EXECUTE_TYPE) - # If True then allocation is using NtMapViewOfSection - self.settings["ProcInject_AllocationMethod"] = packedSetting(52, confConsts.TYPE_SHORT, enum=self.ALLOCATION_FUNCTIONS) - - # Unknown data, silencing for now - # self.settings["ProcInject_Stub"] = packedSetting(53, confConsts.TYPE_STR, 16, isBlob=True) - self.settings["bUsesCookies"] = packedSetting(50, confConsts.TYPE_SHORT, isBool=True) - self.settings["HostHeader"] = packedSetting(54, confConsts.TYPE_STR, 128) - - -class cobaltstrikeConfig: - def __init__(self, data): - self.data = data - - """Parse the CobaltStrike configuration""" - - @staticmethod - def decode_config(cfg_blob, version): - return bytes(cfg_offset ^ confConsts.XORBYTES[version] for cfg_offset in cfg_blob) - - def _parse_config(self, version, quiet=False, as_json=False): - parsed_config = {} - comp_pattern = re.compile(confConsts.START_PATTERNS[version], re.DOTALL) - re_start_match = comp_pattern.search(self.data) - comp_pattern_decoded = re.compile(confConsts.START_PATTERN_DECODED, re.DOTALL) - re_start_decoded_match = comp_pattern_decoded.search(self.data) - - if not re_start_match and not re_start_decoded_match: - return False - encoded_config_offset = re_start_match.start() if re_start_match else -1 - decoded_config_offset = re_start_decoded_match.start() if re_start_decoded_match else -1 - - if encoded_config_offset >= 0: - full_config_data = cobaltstrikeConfig.decode_config( - self.data[encoded_config_offset : encoded_config_offset + confConsts.CONFIG_SIZE], version=version - ) - else: - full_config_data = self.data[decoded_config_offset : decoded_config_offset + confConsts.CONFIG_SIZE] - - settings = BeaconSettings(version).settings.items() - for conf_name, packed_conf in settings: - parsed_setting = packed_conf.pretty_repr(full_config_data) - - if as_json: - parsed_config[conf_name] = parsed_setting - continue - - if parsed_setting == "Not Found" and quiet: - continue - if not isinstance(parsed_setting, list): - log.debug("{: <{width}} - {val}".format(conf_name, width=COLUMN_WIDTH - 3, val=parsed_setting)) - elif parsed_setting == []: - log.debug("{: <{width}} - {val}".format(conf_name, width=COLUMN_WIDTH - 3, val="Empty")) - else: - log.debug("{: <{width}} - {val}".format(conf_name, width=COLUMN_WIDTH - 3, val=parsed_setting[0])) - for val in parsed_setting[1:]: - log.debug(" " * COLUMN_WIDTH, end="") - print(val) - - if as_json: - return parsed_config - - return True - - def parse_config(self, version=None, quiet=False, as_json=False): - """ - Parses beacon's configuration from stager dll or memory dump - :bool quiet: Whether to print missing settings - :bool as_json: Whether to dump as json - """ - - if not version: - for ver in SUPPORTED_VERSIONS: - conf = self._parse_config(version=ver, quiet=quiet, as_json=as_json) - if conf: - return conf - else: - conf = self._parse_config(version=version, quiet=quiet, as_json=as_json) - if conf: - return conf - - if __name__ == "__main__": - log.debug("Configuration not found. Are you sure this is a beacon?") - return None - - def parse_encrypted_config(self, version=None, quiet=False, as_json=False): - """ - Parses beacon's configuration from stager dll or memory dump - :bool quiet: Whether to print missing settings - :bool as_json: Whether to dump as json - """ - - THRESHOLD = 1100 - try: - pe = pefile.PE(data=self.data) - except pefile.PEFormatError: - return {} - data_sections = [s for s in pe.sections if s.Name.find(b".data") != -1] - if not data_sections: - return None - data = data_sections[0].get_data() - - offset = 0 - key_found = False - while offset < len(data): - key = data[offset : offset + 4] - if key != bytes(4) and data.count(key) >= THRESHOLD: - key_found = True - size = int.from_bytes(data[offset - 4 : offset], "little") - encrypted_data_offset = offset + 16 - (offset % 16) - break - - offset += 4 - - if not key_found: - log.debug("Failed to find encrypted data (try to lower the threshold constant)") - return None - - # decrypt and parse - enc_data = data[encrypted_data_offset : encrypted_data_offset + size] - dec_data = [c ^ key[i % 4] for i, c in enumerate(enc_data)] - dec_data = bytes(dec_data) - return cobaltstrikeConfig(dec_data).parse_config(version, quiet, as_json) - - -if __name__ == "__main__": - parser = argparse.ArgumentParser(description="Parses CobaltStrike Beacon's configuration from PE or memory dump.") - parser.add_argument("path", help="Stager's file path") - parser.add_argument("--json", help="Print as json", action="store_true", default=False) - parser.add_argument("--quiet", help="Do not print missing settings", action="store_true", default=False) - parser.add_argument( - "--version", - help="Try as specific cobalt version (3 or 4). If not specified, tries both. \n" - "For decoded configs, this must be set for accuracy.", - type=int, - ) - args = parser.parse_args() - data = Path(args.path).read_bytes() - parsed_config = cobaltstrikeConfig(data).parse_config(version=args.version, quiet=args.quiet, as_json=args.json) - if parsed_config is None: - parsed_config = cobaltstrikeConfig(data).parse_encrypted_config(quiet=args.quiet, as_json=args.json) - if args.json: - print(json.dumps(parsed_config, cls=Base64Encoder)) - - -# CAPE -def extract_config(data): - output = cobaltstrikeConfig(data).parse_config(as_json=True) - if output is None: - output = cobaltstrikeConfig(data).parse_encrypted_config(as_json=True) - return output diff --git a/modules/processing/parsers/CAPE/CobaltStrikeStager.py b/modules/processing/parsers/CAPE/CobaltStrikeStager.py deleted file mode 100644 index f49c0886b87..00000000000 --- a/modules/processing/parsers/CAPE/CobaltStrikeStager.py +++ /dev/null @@ -1,190 +0,0 @@ -#!/usr/bin/env python3 -""" -By Daniel Mayer (Daniel@Stairwell.com), @dan__mayer -""" - -import re -import struct - -DESCRIPTION = "Cobalt Strike Stager Configuration Extractor" -AUTHOR = "@dan__mayer " - -INET_CONSTANTS = { - "INTERNET_FLAG_IDN_DIRECT": 0x00000001, - "INTERNET_FLAG_IDN_PROXY": 0x00000002, - "INTERNET_FLAG_RELOAD": 0x80000000, - "INTERNET_FLAG_RAW_DATA": 0x40000000, - "INTERNET_FLAG_EXISTING_CONNECT": 0x20000000, - "INTERNET_FLAG_ASYNC": 0x10000000, - "INTERNET_FLAG_PASSIVE": 0x08000000, - "INTERNET_FLAG_NO_CACHE_WRITE": 0x04000000, - "INTERNET_FLAG_MAKE_PERSISTENT": 0x02000000, - "INTERNET_FLAG_FROM_CACHE": 0x01000000, - "INTERNET_FLAG_SECURE": 0x00800000, - "INTERNET_FLAG_KEEP_CONNECTION": 0x00400000, - "INTERNET_FLAG_NO_AUTO_REDIRECT": 0x00200000, - "INTERNET_FLAG_READ_PREFETCH": 0x00100000, - "INTERNET_FLAG_NO_COOKIES": 0x00080000, - "INTERNET_FLAG_NO_AUTH": 0x00040000, - "INTERNET_FLAG_RESTRICTED_ZONE": 0x00020000, - "INTERNET_FLAG_CACHE_IF_NET_FAIL": 0x00010000, - "INTERNET_FLAG_IGNORE_REDIRECT_TO_HTTP": 0x00008000, - "INTERNET_FLAG_IGNORE_REDIRECT_TO_HTTPS": 0x00004000, - "INTERNET_FLAG_IGNORE_CERT_DATE_INVALID": 0x00002000, - "INTERNET_FLAG_IGNORE_CERT_CN_INVALID": 0x00001000, - "INTERNET_FLAG_RESYNCHRONIZE": 0x00000800, - "INTERNET_FLAG_HYPERLINK": 0x00000400, - "INTERNET_FLAG_NO_UI": 0x00000200, - "INTERNET_FLAG_PRAGMA_NOCACHE": 0x00000100, - "INTERNET_FLAG_CACHE_ASYNC": 0x00000080, - "INTERNET_FLAG_FORMS_SUBMIT": 0x00000040, - "INTERNET_FLAG_FWD_BACK": 0x00000020, - "INTERNET_FLAG_NEED_FILE": 0x00000010, -} - -SMB_TEMPLATE = re.compile( - b""" - # Arguments to call API-Hashed CreateNamedPipeA - \x68\x00\xB0\x04\x00 # push 4B000h - \x68\x00\xB0\x04\x00 # push 4B000h - \x6A\x01 # push 1 - \x6A\x06 # push 6 - \x6A\x03 # push 3 - \x52 # push edx - \x68\x45\x70\xDF\xD4 # push 0D4DF7045h - .{110,180} - \xE8.\xFF\xFF\xFF # Call to listen on the named pipe that uses the - # return address to pass the pipe name as an argument - - (?P.{3,140}) # Name of pipe - \x00 # Null terminator at the end of the pipe string - (?P.{4})? # Watermark -""", - re.DOTALL | re.VERBOSE, -) - -DNS_TEMPLATE = re.compile( - b""" - \x69\x50\x68\x64\x6E # DNS api import - .{100,160} - \xE8.\xFF\xFF\xFF # Call to perform DNS stager requests that uses the - # return address to pass the stager domain as an argument - - \x00 # Null byte at the beginning of the domain string - (?P.{63}) # Domain string - ( # CS 4.0 stager-specific - .{90,130} - \x89\xD7\x81\xC7 - .{4} - \xFF\xE7 - (?P.{4})? # Watermark - )? -""", - re.DOTALL | re.VERBOSE, -) - -HTTP_TEMPLATE = re.compile( - b""" - (?:\xC1\x41\xB8|\x51\x51\x68) - (?P.{4}) # Specified port - .{10,50}\x68 - (?P....) # HttpOpenRequestA flags - \x52\x52.{40,140} - - \xE8.\xFF\xFF\xFF # Call to perform HttpOpenRequestA and HttpSendRequestA - # that uses the return address to pass the path - # and headers as an argument - - (?P.{79}) # URL path string - \x00 # Null terminator ending the path string - (?P.{303}) # Header strings, separated by CLRF - \x00 # Null terminator ending the header string - .{60,120} - - \xE8.\xFD\xFF\xFF # Call to perform InternetOpenA, which uses the return - # address to pass the netloc as an argument. - - (?P.+?) # Netloc string - \x00 # Null terminator ending the netloc string - (?P.{4})? # Watermark -""", - re.DOTALL | re.VERBOSE, -) - - -class StagerConfig: - def __init__(self, data): - """ - f: file path - """ - self.data = data - self.config = {} - self._parse_config() - - def _clean(self, s, data_type): - """ - s: bytestring to clean - data_type: string determining which cleaning method is appropriate - - Converts the bytes of the various stager fields into human-readable settings - """ - result = None - if data_type == "string": - result = s.split(b"\x00")[0].decode("utf-8") - elif data_type == "headers": - headers = self._clean(s, "string") - lines = headers.split("\r\n")[:-1] - result = {k: v for k, v in (line.split(": ") for line in lines)} - elif data_type == "port": - result = struct.unpack("I", s)[0] - elif data_type == "inet_flags": - n = struct.unpack(". - -DESCRIPTION = "DoppelPaymer configuration parser." -AUTHOR = "kevoreilly" - -import string - -import pefile -from Cryptodome.Cipher import ARC4 - -rule_source = """ -rule DoppelPaymer -{ - meta: - author = "kevoreilly" - description = "DoppelPaymer Payload" - cape_type = "DoppelPaymer Payload" - - strings: - $getproc32 = {81 FB ?? ?? ?? ?? 74 2D 8B CB E8 ?? ?? ?? ?? 85 C0 74 0C 8B C8 8B D7 E8 ?? ?? ?? ?? 5B 5F C3} - $cmd_string = "Setup run\\n" wide - condition: - uint16(0) == 0x5A4D and all of them -} -""" - -LEN_BLOB_KEY = 40 - - -def convert_char(c) -> str: - if isinstance(c, int): - c = chr(c) - if c in string.printable: - return c - return f"\\x{ord(c):02x}" - - -def decrypt_rc4(key, data): - cipher = ARC4.new(key) - return cipher.decrypt(data) - - -def extract_rdata(pe): - for section in pe.sections: - if b".rdata" in section.Name: - return section.get_data(section.VirtualAddress, section.SizeOfRawData) - return None - - -def extract_config(filebuf): - pe = pefile.PE(data=filebuf, fast_load=False) - config = {} - blobs = filter(None, [x.strip(b"\x00\x00\x00\x00") for x in extract_rdata(pe).split(b"\x00\x00\x00\x00")]) - for blob in blobs: - if len(blob) < LEN_BLOB_KEY: - continue - raw = decrypt_rc4(blob[:LEN_BLOB_KEY][::-1], blob[LEN_BLOB_KEY:]) - if not raw: - continue - for item in raw.split(b"\x00"): - data = "".join(convert_char(c) for c in item) - if len(data) == 406: - config["RSA public key"] = data - elif len(data) > 1 and "\\x" not in data: - config["strings"] = data - return config diff --git a/modules/processing/parsers/CAPE/DridexLoader.py b/modules/processing/parsers/CAPE/DridexLoader.py deleted file mode 100644 index ddee402c654..00000000000 --- a/modules/processing/parsers/CAPE/DridexLoader.py +++ /dev/null @@ -1,175 +0,0 @@ -# Copyright (C) 2018 Kevin O'Reilly (kevin.oreilly@contextis.co.uk) -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU 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 General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import socket -import struct -from contextlib import suppress - -import pefile -import yara -from Cryptodome.Cipher import ARC4 - -DESCRIPTION = "DridexDropper configuration parser." -AUTHOR = "kevoreilly" - -rule_source = """ -rule DridexLoader -{ - meta: - author = "kevoreilly" - description = "Dridex v4 dropper C2 parsing function" - cape_type = "DridexLoader Payload" - - strings: - $c2parse_1 = {57 0F 95 C0 89 35 ?? ?? ?? ?? 88 46 04 33 FF 80 3D ?? ?? ?? ?? 00 76 54 8B 04 FD ?? ?? ?? ?? 8D 4D EC 83 65 F4 00 89 45 EC 66 8B 04 FD ?? ?? ?? ?? 66 89 45 F0 8D 45 F8 50} - $c2parse_2 = {89 45 00 0F B7 53 04 89 10 0F B6 4B 0C 83 F9 0A 7F 03 8A 53 0C 0F B6 53 0C 85 D2 7E B7 8D 74 24 0C C7 44 24 08 00 00 00 00 8D 04 7F 8D 8C 00} - $c2parse_3 = {89 08 66 39 1D ?? ?? ?? ?? A1 ?? ?? ?? ?? 0F 95 C1 88 48 04 80 3D ?? ?? ?? ?? 0A 77 05 A0 ?? ?? ?? ?? 80 3D ?? ?? ?? ?? 00 56 8B F3 76 4E 66 8B 04 F5} - $c2parse_4 = {0F B7 C0 89 01 A0 ?? ?? ?? ?? 3C 0A 77 ?? A0 ?? ?? ?? ?? A0 ?? ?? ?? ?? 57 33 FF 84 C0 74 ?? 56 BE} - $c2parse_5 = {0F B7 05 [4] 89 02 89 15 [4] 0F B6 15 [4] 83 FA 0A 7F 07 0F B6 05 [4] 0F B6 05 [4] 85 C0} - $c2parse_6 = {0F B7 53 ?? 89 10 0F B6 4B ?? 83 F9 0A 7F 03 8A 53 ?? 0F B6 53 ?? 85 D2 7E B9} - $botnet_id = {C7 00 00 00 00 00 8D 00 6A 04 50 8D 4C ?? ?? E8 ?? ?? ?? ?? 0F B7 05} - $rc4_key_1 = {56 52 BA [4] 8B F1 E8 [4] 8B C? 5? C3} - $rc4_key_2 = {5? 8B ?9 52 [5-6] E8 [4] 8B C? 5? C3} - condition: - uint16(0) == 0x5A4D and any of them -} -""" - -MAX_IP_STRING_SIZE = 16 # aaa.bbb.ccc.ddd\0 -LEN_BLOB_KEY = 40 -LEN_BOT_KEY = 107 - -yara_rules = yara.compile(source=rule_source) - - -def decrypt_rc4(key, data): - if not key: - return b"" - cipher = ARC4.new(key) - return cipher.decrypt(data) - - -def extract_rdata(pe): - for section in pe.sections: - if b".rdata" in section.Name: - return section.get_data(section.VirtualAddress, section.SizeOfRawData) - return None - - -def extract_config(filebuf): - cfg = {} - pe = pefile.PE(data=filebuf, fast_load=False) - image_base = pe.OPTIONAL_HEADER.ImageBase - line, c2va_offset, delta = 0, 0, 0 - botnet_code, botnet_rva, rc4_decode = 0, 0, 0 - num_ips_rva = 0 - num_ips = 4 - - matches = yara_rules.match(data=filebuf) - if not matches: - return - - for match in matches: - if match.rule != "DridexLoader": - continue - for block in match.strings: - for item in block.instances: - if "$c2parse" in block.identifier: - c2va_offset = item.offset - line = block.identifier - elif "$botnet_id" in block.identifier: - botnet_code = item.offset - elif "$rc4_key" in block.identifier and not rc4_decode: - rc4_decode = item.offset - if line == "$c2parse_6": - c2_rva = struct.unpack("i", filebuf[c2va_offset + 44 : c2va_offset + 48])[0] - image_base - botnet_rva = struct.unpack("i", filebuf[c2va_offset - 7 : c2va_offset - 3])[0] - image_base - num_ips_rva = c2_rva - 1 - elif line == "$c2parse_5": - c2_rva = struct.unpack("i", filebuf[c2va_offset + 75 : c2va_offset + 79])[0] - image_base - botnet_rva = struct.unpack("i", filebuf[c2va_offset + 3 : c2va_offset + 7])[0] - image_base - num_ips_rva = struct.unpack("i", filebuf[c2va_offset + 18 : c2va_offset + 22])[0] - image_base - elif line == "$c2parse_4": - c2_rva = struct.unpack("i", filebuf[c2va_offset + 6 : c2va_offset + 10])[0] - image_base + 1 - elif line == "$c2parse_3": - c2_rva = struct.unpack("i", filebuf[c2va_offset + 60 : c2va_offset + 64])[0] - image_base - delta = 2 - elif line == "$c2parse_2": - c2_rva = struct.unpack("i", filebuf[c2va_offset + 47 : c2va_offset + 51])[0] - image_base - elif line == "$c2parse_1": - c2_rva = struct.unpack("i", filebuf[c2va_offset + 27 : c2va_offset + 31])[0] - image_base - delta = 2 - else: - return - - try: - c2_offset = pe.get_offset_from_rva(c2_rva) - except pefile.PEFormatError: - return - - num_ips = 0 - if num_ips_rva: - num_ips_offset = pe.get_offset_from_rva(num_ips_rva) - ip_data = filebuf[num_ips_offset : num_ips_offset + 1] - if ip_data: - num_ips = struct.unpack("B", filebuf[num_ips_offset : num_ips_offset + 1])[0] - - for _ in range(num_ips): - ip = struct.unpack(">I", filebuf[c2_offset : c2_offset + 4])[0] - c2_address = socket.inet_ntoa(struct.pack("!L", ip)) - port = str(struct.unpack("H", filebuf[c2_offset + 4 : c2_offset + 6])[0]) - - if c2_address and port: - cfg.setdefault("address", []).append(f"{c2_address}:{port}") - - c2_offset += 6 + delta - - if rc4_decode: - zb = struct.unpack("B", filebuf[rc4_decode + 8 : rc4_decode + 9])[0] - if not zb: - rc4_rva = struct.unpack("i", filebuf[rc4_decode + 5 : rc4_decode + 9])[0] - image_base - else: - rc4_rva = struct.unpack("i", filebuf[rc4_decode + 3 : rc4_decode + 7])[0] - image_base - if rc4_rva: - rc4_offset = pe.get_offset_from_rva(rc4_rva) - if not zb: - raw = decrypt_rc4( - filebuf[rc4_offset : rc4_offset + LEN_BLOB_KEY][::-1], - filebuf[rc4_offset + LEN_BLOB_KEY : rc4_offset + LEN_BOT_KEY], - ) - else: - raw = decrypt_rc4( - filebuf[rc4_offset : rc4_offset + LEN_BLOB_KEY], filebuf[rc4_offset + LEN_BLOB_KEY : rc4_offset + LEN_BOT_KEY] - ) - for item in raw.split(b"\x00"): - if len(item) == LEN_BLOB_KEY - 1: - cfg["RC4 key"] = item.split(b";", 1)[0].decode() - - if botnet_code: - botnet_rva = struct.unpack("i", filebuf[botnet_code + 23 : botnet_code + 27])[0] - image_base - if botnet_rva: - with suppress(struct.error): - botnet_offset = pe.get_offset_from_rva(botnet_rva) - botnet_id = struct.unpack("H", filebuf[botnet_offset : botnet_offset + 2])[0] - cfg["Botnet ID"] = str(botnet_id) - - return cfg - - -if __name__ == "__main__": - import sys - from pathlib import Path - - data = Path(sys.argv[1]).read_bytes() - print(extract_config(data)) diff --git a/modules/processing/parsers/CAPE/Emotet.py b/modules/processing/parsers/CAPE/Emotet.py deleted file mode 100644 index 3aeb42326f2..00000000000 --- a/modules/processing/parsers/CAPE/Emotet.py +++ /dev/null @@ -1,832 +0,0 @@ -# Copyright (C) 2017-2021 Kevin O'Reilly (kevin.oreilly@contextis.co.uk) -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU 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 General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import logging -import socket -import struct -from contextlib import suppress -from itertools import cycle -from pathlib import Path - -import pefile -import yara -from Cryptodome.PublicKey import ECC, RSA -from Cryptodome.Util import asn1 - -log = logging.getLogger(__name__) -log.setLevel(logging.INFO) - -try: - from unicorn import UC_ARCH_X86, UC_HOOK_CODE, UC_MODE_64, Uc, UcError - from unicorn.x86_const import UC_X86_REG_R9, UC_X86_REG_RAX, UC_X86_REG_RCX, UC_X86_REG_RDX, UC_X86_REG_RIP, UC_X86_REG_RSP -except ImportError: - log.error("Unicorn not installed") - -AUTHOR = "kevoreilly" - -rule_source = """ -rule Emotet -{ - meta: - author = "kevoreilly" - description = "Emotet Payload" - cape_type = "Emotet Payload" - strings: - $snippet1 = {FF 15 [4] 83 C4 0C 68 40 00 00 F0 6A 18} - $snippet3 = {83 3D [4] 00 C7 05 [8] C7 05 [8] 74 0A 51 E8 [4] 83 C4 04 C3 33 C0 C3} - $snippet4 = {33 C0 C7 05 [8] C7 05 [8] A3 [4] A3 [19] 00 40 A3 [4] 83 3C C5 [4] 00 75 F0 51 E8 [4] 83 C4 04 C3} - $snippet5 = {8B E5 5D C3 B8 [4] A3 [4] A3 [4] 33 C0 21 05 [4] A3 [4] 39 05 [4] 74 18 40 A3 [4] 83 3C C5 [4] 00 75 F0 51 E8 [4] 59 C3} - $snippet6 = {33 C0 21 05 [4] A3 [4] 39 05 [4] 74 18 40 A3 [4] 83 3C C5 [4] 00 75 F0 51 E8 [4] 59 C3} - $snippet7 = {8B 48 ?? C7 [5-6] C7 40 [4] ?? C7 [2] 00 00 00 [0-1] 83 3C CD [4] 00 74 0E 41 89 48 ?? 83 3C CD [4] 00 75 F2} - $snippet8 = {85 C0 74 3? B9 [2] 40 00 33 D2 89 ?8 [0-1] 89 [1-2] 8B [1-2] 89 [1-2] EB 0? 41 89 [1-2] 39 14 CD [2] 40 00 75 F? 8B CE E8 [4] 85 C0 74 05 33 C0 40 5E C3} - $snippet9 = {85 C0 74 4? 8B ?8 [0-1] C7 40 [5] C7 [5-6] C7 40 ?? 00 00 00 00 83 3C CD [4] 00 74 0? 41 89 [2-3] 3C CD [4] 00 75 F? 8B CF E8 [4] 85 C0 74 07 B8 01 00 00 00 5F C3} - $snippetA = {85 C0 74 5? 8B ?8 04 89 78 28 89 38 89 70 2C EB 04 41 89 48 04 39 34 CD [4] 75 F3 FF 75 DC FF 75 F0 8B 55 F8 FF 75 10 8B 4D EC E8 [4] 83 C4 0C 85 C0 74 05} - $snippetB = {EB 04 4? 89 [2] 39 [6] 75 F3} - $snippetC = {EB 03 4? 89 1? 39 [6] 75 F4} - $snippetD = {8D 44 [2] 50 68 [4] FF 74 [2] FF 74 [2] 8B 54 [2] 8B 4C [2] E8} - $snippetE = {FF 74 [2] 8D 54 [2] FF 74 [2] 68 [4] FF 74 [2] 8B 4C [2] E8 [4] 8B 54 [2] 83 C4 10 89 44 [2] 8B F8 03 44 [2] B9 [4] 89 44 [2] E9 [2] FF FF} - $snippetF = {FF 74 [2] 8D 44 [2] BA [4] FF 74 [2] 8B 4C [2] 50 E8 [4] 8B 54 [2] 8B D8 8B 84 [5] 83 C4 0C 03 C3 89 5C [2] 8B FB 89 44} - $snippetG = {FF 74 [2] 8B 54 [2] 8D 44 [2] 8B 4C [2] 50 E8 [4] 8B D0 83 C4 0C 8B 44 [2] 8B FA 03 C2 89 54 [2] 89 44} - $snippetH = {FF 74 [2] 8D 84 [5] 68 [4] 50 FF 74 [2] 8B 54 [2] 8B 4C [2] E8 [4] 8B 94 [5] 83 C4 10 89 84 [5] 8B F8 03 84} - $snippetI = {FF 74 [2] 8D 8C [5] FF 74 [2] 8B 54 [2] E8 [4] 8B 54 [2] 8B D8 8B 84 [5] 83 C4 0C 03 C3 89 5C [2] 8B FB 89 44 24 74} - $snippetJ = {FF 74 [2] 8B 4C [2] 8D 44 [2] 50 BA [4] E8 [4] 8B 54 [2] 8B F8 59 89 44 [2] 03 44 [2] 59 89 44 [2] B9 [4] E9} - $snippetK = {FF 74 [2] FF 74 [2] 8B 54 [2] E8 [4] 8B 54 [2] 83 C4 0C 89 44 [2] 8B F8 03 44 [2] B9 [4] 89 44 [2] E9} - $snippetL = {FF 74 [2] 8B 54 [2] 8D 4C [2] E8 [4] 59 89 44 [2] 8B F8 03 44 [2] 59 89 44 24 68 B9 [4] E9} - $snippetM = {FF 74 [2] 8D 84 [3] 00 00 B9 [4] 50 FF 74 [2] FF 74 [2] 8B 94 [3] 00 00 E8 [4] 83 C4 10 89 44 [2] 8B F8 B9 [4] 03 84 [3] 00 00 89 44 [2] E9} - $snippetN = {FF 74 [2] 8D 44 [2] B9 [4] FF 74 [2] 50 FF 74 [2] 8B 54 [2] E8 [4] 8B 8C [3] 00 00 83 C4 10 03 C8 89 44 [2] 89 4C [2] 8B F8 B9 45 89 77 05 E9} - $snippetO = {8D 44 [2] B9 [4] 50 FF 74 [2] 8B 54 [2] E8 [4] 8B D0 8B 44 [2] 59 59 03 C2 89 54 [2] 8B FA 89 44 [2] B9 [4] E9} - $snippetP = {FF 74 [2] 8B 54 [2] 8D 44 [2] 8B 4C [2] 68 [4] 50 E8 [4] 8B D0 83 C4 0C 8B 44 [2] 8B FA 03 C2 89 54 [2] 8B 54 [2] B9 [4] 89 44 [2] E9} - $snippetQ = {FF 74 [2] BA [4] 8D 4C [2] FF 74 [2] E8 [4] 59 89 84 [3] 00 00 8B F8 03 44 [2] 59 89 44 [2] B9 [4] 81 F9 [4] 74 28 8B 54 [2] E9} - $snippetR = {8D 44 [2] 50 FF 74 [2] 8B 54 [2] 8B 4C [2] 68 [4] E8 [4] 8B D0 83 C4 0C 8B 44 [2] 8B FA 03 C2 89 54 [2] 8B 54 [2] B9 [4] 89 44 [2] E9} - $snippetS = {FF 74 [2] 8D 54 [2] FF 74 [2] 8B 4C [2] E8 [4] 8B D0 83 C4 0C 8B 44 [2] 8B FA 03 C2 89 54 [2] 8B 54 [2] B9 [4] 89 44 [2] E9} - $snippetT = {8B 54 [2] 8D 44 [2] 8B 4C [2] 68 [4] 50 E8 [4] 8B 9C [3] 00 00 8B F8 59 59 03 D8 89 44 [2] 89 5C [2] B9 [4] EB} - $snippetU = {89 44 [2] 33 D2 8B 44 [2] F7 F1 B9 [4] 89 44 [2] 8D 44 [2] 81 74 [6] C7 44 [6] 81 44 [6] 81 74 [6] FF 74 [2] 50 FF 74 [2] FF 74 [2] 8B 54 [2] E8} - $snippetV = {81 74 [2] ED BC 9C 00 FF 74 [2] 50 68 [4] FF 74 [2] 8B 54 [2] 8B 4C [2] E8} - $snippetW = {4C 8D [2] 8B [2] 4C 8D 05 [4] F7 E1 2B CA D1 E9 03 CA C1 E9 06 89} - $snippetX = {4C 8D 0? [2] (00|01) 00 [0-80] 48 8D [0-9] 81 75 [5] C7 45 [5-14] 81} - $snippetY = {(3D [4] 0F 84 [4] 3D [4] 0F 85 [3] ??|B8 [4] E9 [3] ??) 48 8D 05 [4] 48 89 (81 [3] ??|41 ??) 48 8D 05 [4] 48 89 (81 [3] ??|41 ??) 48 8D 05 [4] 48 89} - $snippetZ = {(48 8B D8 48 85 C0 0F 84 [4-9] E9 [4-190] ?? | 55 53 48 8D AC 24 [2] FF FF 48 81 EC [2] 00 00 48 8B [3] 00 00 [0-80] ??) 48 8D 05 [4] 48 89 (85 [3] ??|4? ??) [0-220] 48 8D 05 [4] 48 89 (85 [3] ??|4? ??) [0-220] 48 8D 05 [4] 48 89 (85 [3] ??|4? ??)} - $comboA1 = {83 EC 28 56 FF 75 ?? BE} - $comboA2 = {83 EC 38 56 57 BE} - $comboA3 = {EB 04 40 89 4? ?? 83 3C C? 00 75 F6} - $ref_rsa = {6A 00 6A 01 FF [4-9] C0 [5-11] E8 ?? ?? FF FF 8D 4? [1-2] B9 ?? ?? ?? 00 8D 5? [4-6] E8} - $ref_ecc1 = {8D 84 [5] 50 68 [4] FF B4 24 [4] FF B4 24 [4] 8B 94 24 [4] 8B 8C 24 [4] E8 [4] 89 84 24 [4] 8D 84 24 [4] 50 68 [4] FF B4 24 [4] FF B4 24 [4] 8B 54 24 40 8B 8C 24 [4] E8} - $ref_ecc2 = {FF B4 [3] 00 00 8D 94 [3] 00 00 FF B4 [3] 00 00 68 [4] FF 74 [2] 8B 8C [3] 00 00 E8 [4] FF B4 [3] 00 00 8D 94 [3] 00 00 89 84 [3] 00 00 FF B4 [3] 00 00 68 [4] FF 74 [2] 8B 8C [3] 00 00 E8} - $ref_ecc3 = {8D 84 [5] BA [4] FF B4 [5] 8B 4C [2] 50 E8 [4] 83 C4 0C 89 84 [5] 8D 84 [5] BA [4] FF B4 [5] FF B4 [5] 8B 8C [5] 50 E8 05 05 01 00} - $ref_ecc4 = {FF 74 [2] 8B 94 [5] 8D 84 [5] 8B 8C [5] 50 E8 [4] 83 C4 0C 89 84 [5] 8D 84 [5] 68 [4] FF B4 [5] 8B 54 [2] 8B 8C [5] 50 E8} - $ref_ecc5 = {FF B4 [3] 00 00 8D 84 [3] 00 00 68 [4] 50 FF B4 [3] 00 00 8B 94 [3] 00 00 8B 4C [2] E8 [4] FF B4 [3] 00 00 89 84 [3] 00 00 8D 84} - $ref_ecc6 = {FF B4 [3] 00 00 8D 8C [3] 00 00 FF B4 [3] 00 00 8B 54 [2] E8 [4] 83 C4 0C 89 84 [5] 8D 8C [5] 68 [4] FF B4 [5] FF 74 [2] 8B 94 24 [4] E8} - $ref_ecc7 = {FF B4 [3] 00 00 8B 8C [3] 00 00 8D 84 [3] 00 00 50 BA [4] E8 [4] FF B4 [3] 00 00 8B 8C [3] 00 00 BA [4] 89 84 [3] 00 00 8D 84 [3] 00 00 50 E8} - $ref_ecc8 = {FF B4 [3] 00 00 FF B4 [3] 00 00 8B 94 [3] 00 00 E8 [4] 83 C4 0C 89 84 [3] 00 00 8D 84 [3] 00 00 B9 [4] 50 FF B4 [3]00 00 FF B4 [3]00 00 8B 94 [3]00 00 E8} - $ref_ecc9 = {FF B4 [3] 00 00 8B 54 [2] 8D 8C [3] 00 00 E8 [4] 68 [4] FF B4 [3] 00 00 8B 94 [3] 00 00 8D 8C [3] 00 00 89 84 [3] 00 00 E8} - $ref_eccA = {FF 74 [2] 8D 84 [3] 00 00 B9 [4] 50 FF 74 [2] FF B4 [3] 00 00 8B 94 [3] 00 00 E8 [4] FF B4 [3] 00 00 89 84 [3] 00 00 B9 [4] 8D 84 [3] 00 00 50} - $ref_eccB = {FF B4 [3] 00 00 8D 84 [3] 00 00 B9 [4] FF 74 [2] 50 FF B4 [3] 00 00 8B 94 [3] 00 00 E8 [4] FF B4 [3] 00 00 89 84 [3] 00 00 B9} - $ref_eccC = {8D 84 [3] 00 00 B9 [4] 50 FF 74 [2] 8B 94 [3] 00 00 E8 [4] 89 84 [3] 00 00 B9 [4] 8D 84 [3] 00 00 50 FF B4 [3] 00 00 8B 94 [3] 00 00 E8} - $ref_eccD = {FF B4 [3] 00 00 8B 54 [2] 8D 84 [3] 00 00 8B 8C [3] 00 00 68 [4] 50 E8 [4] 83 C4 0C 89 84 [3] 00 00 8D 84 [3] 00 00 FF B4 [3] 00 00 8B 94 [3] 00 00 8B 4C [2] 68 [4] 50 E8} - $ref_eccE = {FF B4 [3] 00 00 BA [4] 8D 8C [3] 00 00 FF B4 [3] 00 00 E8 [4] FF 74 [2] BA [4] 89 84 [3] 00 00 FF 74 [2] 8D 8C [3] 00 00 E8} - $ref_eccF = {FF B4 [3] 00 00 8D 94 [3] 00 00 FF B4 [3] 00 00 8B 4C [2] E8 [4] 83 C4 0C 89 84 [3] 00 00 8D 94 [3] 00 00 68 [4] FF 74 [2] FF B4 [3] 00 00 8B 4C [2] E8} - $ref_eccG = {8D 84 [3] 00 00 50 FF B4 [3] 00 00 8B 94 [3] 00 00 8B 8C [3] 00 00 68 [4] E8 [4] 83 C4 0C 89 84 [3] 00 00 8D 84 [3] 00 00 50 FF 74 [2] 8B 94 [3] 00 00 8B 8C [3] 00 00 68 [4] E8} - $ref_eccH = {8D 84 [5] 50 68 [4] FF 74 [2] FF B4 [3] 00 00 8B 94 [3] 00 00 8B 8C [3] 00 00 E8 [4] 89 84 [3] 00 00 8D 84 [3] 00 00 50 68} - $ref_eccI = {8B 94 [3] 00 00 8D 84 [3] 00 00 8B 8C [3] 00 00 68 [4] 50 E8 [4] 8B 54 [2] 8B 8C [3] 00 00 89 84 [3] 00 00 8D 84 [3] 00 00 68 [4] 50 E8} - $ref_eccJ = {8B 44 [2] 6A 6D 59 F7 F1 B9 [4] 89 44 [2] 8D 44 [2] 81 74 [6] C7 44 [6] C1 64 [3] C1 6C [3] 81 74 [6] C7 44 [6] 81 44 [6] 81 4C [6] 81 74 [6] FF 74 [2] 50 FF 74 [2] FF 74 [2] 8B 54 [2] E8} - $ref_eccK = {81 74 [2] 82 8D 0C 00 FF 74 [2] 50 68 [4] FF 74 [2] 8B 54 [2] 8B 4C [2] E8} - $ref_eccL = {4C 8D [3] 4C 8D [5] 81 85 ?? 00 00 00 [4] 81 B5 ?? 00 00 00 [4] C7 85 ?? 00 00 00} - $ref_eccM = {4C 8D 0D [4] 81 B5 ?? 00 00 00 [4] 81 B5 ?? 00 00 00 [4] C7 85 ?? 00 00 00 [4] 81 B5 ?? 00 00 00 [4] 6B 85} - $ref_eccN = {4C 8D 05 [4-28] F7 E1 2B CA D1 E9 03 CA C1 E9 05 89 8D ?? 00 00 00 C1 AD ?? 00 00 00 ?? 81 B5 ?? 00 00 00} - $ref_eccO = {4C 8D 0D [4] 8B 45 ?? 8D 0C ?? B8 [4] 03 C9 89 4D ?? 8B 4D ?? F7 E1 B8 [4] 2B CA D1 E9 03 CA C1 E9 05} - $ref_eccP = {40 55 48 8D 6C 24 ?? 48 81 EC [12-36] C7 45 [4] 00 [0-60] C7 45 [4] 00 [0-60] C7 45 [4] 00 [0-60] C7 45} - condition: - uint16(0) == 0x5A4D and any of ($snippet*) or 2 of ($comboA*) or $ref_rsa or any of ($ref_ecc*) -} -""" - -MAX_IP_STRING_SIZE = 16 # aaa.bbb.ccc.ddd\0 - - -def first_match(matches, pattern): - if not matches: - return 0 - for item in matches[0].strings: - if pattern == item.identifier: - return item.instances[0].offset - return 0 - - -def addresses_from_matches(matches, pattern): - addresses = [] - for match in matches: - for item in match.strings: - if item.identifier == pattern: - addresses.append(item.instances[0].offset) - return addresses - - -def c2_funcs_from_match(matches, pattern, data): - addresses = [] - addr = first_match(matches, pattern) - hit = addr + data[addr:].find(b"\x48\x8D\x05") - next = 1 - while next > 0: - addresses.append(struct.unpack("i", data[hit + 3 : hit + 7])[0] + hit + 7) - next = data[hit + 7 : hit + 600].find(b"\x48\x8D\x05") - if next != -1: - hit += next + 7 - return addresses - - -def xor_data(data, key): - return bytes(c ^ k for c, k in zip(data, cycle(key))) - - -def emotet_decode(data, size, xor_key): - offset = 8 - res = b"" - for count in range(int(size / 4)): - off_from = offset + count * 4 - off_to = off_from + 4 - encoded_dw = int.from_bytes(data[off_from:off_to], byteorder="little") - decoded = xor_key ^ encoded_dw - res += decoded.to_bytes(4, byteorder="little") - return res - - -# Thanks to Jason Reaves (@sysopfb), @pollo290987, phate1. -def extract_emotet_rsakey(pe): - for section in pe.sections: - if section.Name.replace(b"\x00", b"") == b".data": - data_section = section.get_data() - data_size = len(data_section) - res_list = [] - if data_size: - delta = 0 - while delta < data_size: - xor_key = int.from_bytes(data_section[delta : delta + 4], byteorder="little") - encoded_size = int.from_bytes(data_section[delta + 4 : delta + 8], byteorder="little") - decoded_size = ((xor_key ^ encoded_size) & 0xFFFFFFFC) + 4 - if decoded_size == 0x6C: - res_list.append(emotet_decode(data_section[delta:], decoded_size, xor_key)) - break - delta += 4 - if res_list: - res_list = list(set(res_list)) - pub_key = res_list[0][:106] - seq = asn1.DerSequence() - try: - seq.decode(pub_key) - except Exception as e: - logging.exception(e) - return - return RSA.construct((seq[0], seq[1])) - for section in pe.sections: - if section.Name.replace(b"\x00", b"") == b".text": - code_section = section.get_data() - code_size = len(code_section) - if code_size: - delta = 0 - while delta < code_size: - xor_key = int.from_bytes(code_section[delta : delta + 4], byteorder="little") - encoded_size = int.from_bytes(code_section[delta + 4 : delta + 8], byteorder="little") - decoded_size = ((xor_key ^ encoded_size) & 0xFFFFFFFC) + 4 - if decoded_size == 0x6C: - res_list.append(emotet_decode(code_section[delta:], decoded_size, xor_key)) - break - delta += 4 - if res_list: - res_list = list(set(res_list)) - pub_key = res_list[0][:106] - seq = asn1.DerSequence() - try: - seq.decode(pub_key) - except ValueError: - # log.error(e) - return - return RSA.construct((seq[0], seq[1])) - - -stack = 0x80000 -code_base = 0x180001000 - - -def hook_instr(uc, address, size, mode): - global call_count - ins = uc.mem_read(address + size, 1) - if ins == (b"\xe8"): - call_count = call_count + 1 - if call_count == 4: - call_count = 0 - uc.reg_write(UC_X86_REG_RAX, stack + 0x400) - uc.reg_write(UC_X86_REG_RIP, uc.reg_read(UC_X86_REG_RIP) + 9) - return True - - -def emulate(code, ep): - global call_count - call_count = 0 - with suppress(UcError): - uc = Uc(UC_ARCH_X86, UC_MODE_64) - size = int(len(code) / 0x1000) * 0x1000 - if len(code) % 0x1000: - size = size + 0x1000 - uc.mem_map(code_base, size) - uc.mem_write(code_base, code) - uc.mem_map(stack, 0x1000) - uc.mem_map(0x0, 0x1000) - uc.reg_write(UC_X86_REG_RSP, stack + 0x200) - uc.reg_write(UC_X86_REG_RCX, stack + 0x104) - uc.reg_write(UC_X86_REG_RDX, stack + 0x108) - uc.reg_write(UC_X86_REG_R9, stack + 0x108) - uc.hook_add(UC_HOOK_CODE, hook_instr, user_data=UC_MODE_64) - uc.emu_start(code_base + ep, code_base + len(code)) - return uc - - -def have_enough_memory_for_unicorn(): - """ - Avoid unicorn calling exit(1) due to memory leak. - - https://github.com/unicorn-engine/unicorn/issues/1766 - - https://github.com/unicorn-engine/unicorn/pull/1629 - """ - try: - from mmap import MAP_ANON, MAP_PRIVATE, PROT_EXEC, PROT_READ, PROT_WRITE, mmap - - mm = mmap( - -1, - 1024 * 1024 * 1024, - MAP_PRIVATE | MAP_ANON, - PROT_WRITE | PROT_READ | PROT_EXEC, - ) - mm.close() - return True - except OSError: - return False - - -def extract_config(filebuf): - conf_dict = {} - pe = None - with suppress(Exception): - pe = pefile.PE(data=filebuf, fast_load=False) - code = filebuf[pe.sections[0].PointerToRawData : pe.sections[0].PointerToRawData + pe.sections[0].SizeOfRawData] - - if pe is None: - return - - image_base = pe.OPTIONAL_HEADER.ImageBase - c2found = False - c2list_va_offset = 0 - c2_list_offset = 0 - delta = 0 - c2_funcs = [] - ecc_funcs = [] - - yara_rules = yara.compile(source=rule_source) - yara_matches = yara_rules.match(data=filebuf) - - if first_match(yara_matches, "$snippet3"): - c2list_va_offset = first_match(yara_matches, "$snippet3") - c2_list_va = struct.unpack("I", filebuf[c2list_va_offset + 2 : c2list_va_offset + 6])[0] - c2_list_rva = c2_list_va & 0xFFFF if c2_list_va - image_base > 0x20000 else c2_list_va - image_base - try: - c2_list_offset = pe.get_offset_from_rva(c2_list_rva) - except pefile.PEFormatError: - pass - - while True: - try: - ip = struct.unpack(" 0x20000 else c2_list_va - image_base - try: - c2_list_offset = pe.get_offset_from_rva(c2_list_rva) - except pefile.PEFormatError: - pass - while True: - try: - ip = struct.unpack(" 0x40000 else c2_list_va - image_base - try: - c2_list_offset = pe.get_offset_from_rva(c2_list_rva) - except pefile.PEFormatError as err: - log.error(err) - return - while True: - preip = filebuf[c2_list_offset : c2_list_offset + 4] - if not preip: - return - try: - ip = struct.unpack(" 0x20000 else c2_list_va - image_base - try: - c2_list_offset = pe.get_offset_from_rva(c2_list_rva) - except pefile.PEFormatError: - pass - while True: - try: - ip = struct.unpack(" 0x20000 else c2_list_va - image_base - try: - c2_list_offset = pe.get_offset_from_rva(c2_list_rva) - except pefile.PEFormatError: - pass - while True: - try: - ip = struct.unpack(" 1000: - log.debug("Anomalous C2 list size 0x%x", size) - return - c2_list_offset += 8 - c2_list = xor_data(filebuf[c2_list_offset:], key) - offset = 0 - while offset < size: - try: - ip = struct.unpack(">I", c2_list[offset : offset + 4])[0] - except Exception: - break - if ip == struct.unpack(">I", key)[0]: - break - c2_address = socket.inet_ntoa(struct.pack("!L", ip)) - port = str(struct.unpack(">H", c2_list[offset + 4 : offset + 6])[0]) - if not c2_address or not port: - break - conf_dict.setdefault("address", []).append(f"{c2_address}:{port}") - c2found = True - offset += 8 - elif c2_funcs: - for address in c2_funcs: - if not have_enough_memory_for_unicorn(): - log.warning("not enough memory for unicorn") - continue - uc = emulate(code, address - pe.sections[0].PointerToRawData) - c2_address = socket.inet_ntoa(struct.pack("!L", int.from_bytes(uc.mem_read(stack + 0x104, 4), byteorder="big"))) - flag = str(int.from_bytes(uc.mem_read(stack + 0x108, 2), byteorder="little")) - port = str(int.from_bytes(uc.mem_read(stack + 0x10A, 2), byteorder="little")) - if flag == "1" and port != "0": - conf_dict.setdefault("address", []).append(f"{c2_address}:{port}") - c2found = True - - if not c2found: - return - pem_key = False - with suppress(ValueError): - pem_key = extract_emotet_rsakey(pe) - if pem_key: - conf_dict.setdefault("RSA public key", pem_key.exportKey().decode()) - else: - if first_match(yara_matches, "$ref_rsa"): - ref_rsa_offset = first_match(yara_matches, "$ref_rsa") - ref_rsa_va = 0 - zb = struct.unpack("b", filebuf[ref_rsa_offset + 31 : ref_rsa_offset + 32])[0] - if not zb: - ref_rsa_va = struct.unpack("I", filebuf[ref_rsa_offset + 28 : ref_rsa_offset + 32])[0] - else: - zb = struct.unpack("b", filebuf[ref_rsa_offset + 29 : ref_rsa_offset + 30])[0] - if not zb: - ref_rsa_va = struct.unpack("I", filebuf[ref_rsa_offset + 26 : ref_rsa_offset + 30])[0] - else: - zb = struct.unpack("b", filebuf[ref_rsa_offset + 28 : ref_rsa_offset + 29])[0] - if not zb: - ref_rsa_va = struct.unpack("I", filebuf[ref_rsa_offset + 25 : ref_rsa_offset + 29])[0] - else: - zb = struct.unpack("b", filebuf[ref_rsa_offset + 38 : ref_rsa_offset + 39])[0] - if not zb: - ref_rsa_va = struct.unpack("I", filebuf[ref_rsa_offset + 35 : ref_rsa_offset + 39])[0] - if not ref_rsa_va: - return - ref_rsa_rva = ref_rsa_va - image_base - try: - ref_rsa_offset = pe.get_offset_from_rva(ref_rsa_rva) - except Exception: - return - key = struct.unpack(". - -DESCRIPTION = "Enfal configuration parser." -AUTHOR = "kevoreilly" - -import yara - -rule_source = """ -rule Enfal -{ - meta: - author = "kev" - description = "Enfal configuration blob" - cape_type = "Enfal Config" - strings: - $config = {BF 49 ?? 75 22 12 ?? 75 4B 65 72 6E 65 6C 33 32 2E 64 6C 6C} - - condition: - $config -} -""" - -MAX_STRING_SIZE = 128 - - -def yara_scan(raw_data, rule_name): - addresses = {} - yara_rules = yara.compile(source=rule_source) - matches = yara_rules.match(data=raw_data) - for match in matches: - if match.rule == "Enfal": - for item in match.strings: - if item.identifier == rule_name: - addresses[item.identifier] = item.instances[0].offset - return addresses - - -def string_from_offset(data, offset): - return data[offset : offset + MAX_STRING_SIZE].split(b"\0", 1)[0] - - -def list_from_offset(data, offset): - string = data[offset : offset + MAX_STRING_SIZE].split(b"\0", 1)[0] - return string.split(b",") - - -def extract_config(filebuf): - config = yara_scan(filebuf, "$config") - return_conf = {} - if config: - yara_offset = int(config["$config"]) - - c2_address = string_from_offset(filebuf, yara_offset + 0x2E8) - if c2_address: - return_conf["c2_address"] = c2_address - - c2_url = string_from_offset(filebuf, yara_offset + 0xE8) - if c2_url: - return_conf["c2_url"] = c2_url - - if filebuf[yara_offset + 0x13B0 : yara_offset + 0x13B1] == "S": - registrypath = string_from_offset(filebuf, yara_offset + 0x13B0) - elif filebuf[yara_offset + 0x13C0 : yara_offset + 0x13C1] == "S": - registrypath = string_from_offset(filebuf, yara_offset + 0x13C0) - elif filebuf[yara_offset + 0x13D0 : yara_offset + 0x13D1] == "S": - registrypath = string_from_offset(filebuf, yara_offset + 0x13D0) - else: - registrypath = "" - - if registrypath: - return_conf["registrypath"] = registrypath - - if filebuf[yara_offset + 0x14A2 : yara_offset + 0x14A3] == "C": - servicename = "" - filepaths = list_from_offset(filebuf, yara_offset + 0x14A2) - filepaths[0] = filepaths[0].split(b" ", 1)[0] - elif filebuf[yara_offset + 0x14B0 : yara_offset + 0x14B1] != "\0": - servicename = string_from_offset(filebuf, yara_offset + 0x14B0) - filepaths = list_from_offset(filebuf, yara_offset + 0x14C0) - elif filebuf[yara_offset + 0x14C0 : yara_offset + 0x14C1] != "\0": - servicename = string_from_offset(filebuf, yara_offset + 0x14C0) - filepaths = list_from_offset(filebuf, yara_offset + 0x14D0) - elif filebuf[yara_offset + 0x14D0 : yara_offset + 0x14D1] != "\0": - servicename = string_from_offset(filebuf, yara_offset + 0x14D0) - filepaths = list_from_offset(filebuf, yara_offset + 0x14E0) - else: - servicename = "" - filepaths = [] - - if servicename: - return_conf["servicename"] = servicename - if filepaths: - for path in filepaths: - return_conf.setdefault("filepath", []).append(path) diff --git a/modules/processing/parsers/CAPE/EvilGrab.py b/modules/processing/parsers/CAPE/EvilGrab.py deleted file mode 100644 index 3e59277fa3c..00000000000 --- a/modules/processing/parsers/CAPE/EvilGrab.py +++ /dev/null @@ -1,110 +0,0 @@ -# Copyright (C) 2015 Kevin O'Reilly kevin.oreilly@contextis.co.uk -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU 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 General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -DESCRIPTION = "EvilGrab configuration parser." -AUTHOR = "kevoreilly" - -import struct - -import pefile -import yara - -rule_source = """ -rule EvilGrab -{ - meta: - author = "kev" - description = "EvilGrab configuration function" - cape_type = "EvilGrab Payload" - strings: - $configure1 = {8D 44 24 ?? 50 6A 01 E8 ?? ?? ?? ?? 85 C0 74 07 33 C0 E9 9? 00 00 00 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 83 F8 07 59 73 ?? 68 ?? ?? ?? ?? 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 68} - $configure2 = {8D 44 24 ?? 50 6A 01 E8 ?? ?? ?? ?? 85 C0 74 07 33 C0 E9 9? 00 00 00 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 83 F8 07 59 73 ?? 68 ?? ?? ?? ?? 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 83} - $configure3 = {8D 95 60 ?? ?? ?? 52 6A 01 E8 ?? ?? ?? ?? 85 C0 74 13 33 C0 8B 4D F4 64 89 0D 00 00 00 00 5F 5E 5B 8B E5 5D C3 BF ?? ?? ?? ?? 83 C9 FF 33 C0 F2 AE} - - condition: - //check for MZ Signature at offset 0 - uint16(0) == 0x5A4D - - and - - $configure1 or $configure2 or $configure3 -} -""" - -MAX_STRING_SIZE = 65 - - -def yara_scan(raw_data): - addresses = {} - yara_rules = yara.compile(source=rule_source) - matches = yara_rules.match(data=raw_data) - for match in matches: - if match.rule == "EvilGrab": - for item in match.strings: - addresses[item.identifier] = item.instances[0].offset - return addresses - - -def pe_data(pe, va, size): - image_base = pe.OPTIONAL_HEADER.ImageBase - rva = va - image_base - return pe.get_data(rva, size) - - -def string_from_va(pe, offset): - image_base = pe.OPTIONAL_HEADER.ImageBase - string_rva = struct.unpack("i", pe.__data__[offset : offset + 4])[0] - image_base - string_offset = pe.get_offset_from_rva(string_rva) - return pe.__data__[string_offset : string_offset + MAX_STRING_SIZE].split(b"\0", 1)[0] - - -map_offset = { - "$configure1": [24, 71, 60, 90, 132, 186], - "$configure2": [27, 78, 67, 91, 133, 188], - "$configure3": [38, 99, 132, 167, 195], -} - - -def extract_config(filebuf): - pe = pefile.PE(data=filebuf, fast_load=False) - # image_base = pe.OPTIONAL_HEADER.ImageBase - yara_matches = yara_scan(filebuf) - end_config = {} - for key, values in map_offset.keys(): - if not yara_matches.get(key): - continue - - yara_offset = int(yara_matches[key]) - - c2_address = string_from_va(pe, yara_offset + values[0]) - if c2_address: - end_config["c2_address"] = c2_address - port = str(struct.unpack("h", filebuf[yara_offset + values[1] : yara_offset + values[1] + 2])[0]) - if port: - end_config["port"] = [port, "tcp"] - missionid = string_from_va(pe, yara_offset + values[3]) - if missionid: - end_config["missionid"] = missionid - version = string_from_va(pe, yara_offset + values[4]) - if version: - end_config["version"] = version - injectionprocess = string_from_va(pe, yara_offset + values[5]) - if injectionprocess: - end_config["injectionprocess"] = injectionprocess - if key != "$configure3": - mutex = string_from_va(pe, yara_offset - values[6]) - if mutex: - end_config["mutex"] = mutex - - return end_config diff --git a/modules/processing/parsers/CAPE/Fareit.py b/modules/processing/parsers/CAPE/Fareit.py deleted file mode 100644 index c72482cc304..00000000000 --- a/modules/processing/parsers/CAPE/Fareit.py +++ /dev/null @@ -1,69 +0,0 @@ -import re -import sys -from pathlib import Path - -""" -rule pony { - meta: - author = "adam" - description = "Detect pony" - - strings: - $s1 = "{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}" - $s2 = "YUIPWDFILE0YUIPKDFILE0YUICRYPTED0YUI1.0" - - condition: - $s1 and $s2 -} -""" - - -gate_url = re.compile(b".*\\.php$") -exe_url = re.compile(b".*\\.exe$") -dll_url = re.compile(b".*\\.dll$") - - -def extract_config(memdump_path, read=False): - if read: - F = Path(memdump_path).read_bytes() - else: - F = memdump_path - """ - # Get the aPLib header + data - buf = re.findall(r"aPLib .*PWDFILE", cData, re.DOTALL|re.MULTILINE) - # Strip out the header - if buf and len(buf[0]) > 200: - cData = buf[0][200:] - """ - artifacts_raw = { - "controllers": [], - "downloads": [], - } - - start = F.find(b"YUIPWDFILE0YUIPKDFILE0YUICRYPTED0YUI1.0") - if start: - F = F[start - 600 : start + 500] - - output = re.findall( - b"(https?://.[A-Za-z0-9-\\.\\_\\~\\:\\/\\?\\#\\[\\]\\@\\!\\$\\&'\\(\\)\\*\\+\\,\\;\\=]+(?:\\.php|\\.exe|\\.dll))", F - ) - for url in output: - try: - if b"\x00" not in url: - # url = self._check_valid_url(url) - if url is None: - continue - if gate_url.match(url): - artifacts_raw["controllers"].append(url.lower().decode()) - elif exe_url.match(url) or dll_url.match(url): - artifacts_raw["downloads"].append(url.lower().decode()) - except Exception as e: - print(e, sys.exc_info(), "PONY") - artifacts_raw["controllers"] = list(set(artifacts_raw["controllers"])) - artifacts_raw["downloads"] = list(set(artifacts_raw["downloads"])) - return artifacts_raw if len(artifacts_raw["controllers"]) != 0 or len(artifacts_raw["downloads"]) != 0 else False - - -if __name__ == "__main__": - res = extract_config(sys.argv[1], read=True) - print(res) diff --git a/modules/processing/parsers/CAPE/Formbook.py b/modules/processing/parsers/CAPE/Formbook.py deleted file mode 100644 index d24980fc78b..00000000000 --- a/modules/processing/parsers/CAPE/Formbook.py +++ /dev/null @@ -1,22 +0,0 @@ -def extract_config(data): - config_dict = {} - i = 0 - try: - lines = data.decode().split("\n") - except Exception: - return - if lines[0].startswith("POST"): - while lines[i] != "dat=": - i += 1 - if lines[i] == "dat=": - i += 1 - elif "www." not in lines[0]: - return - config_dict["C2"] = lines[i] - decoys = [] - i += 1 - while len(lines[i]) > 0: - decoys.append(lines[i]) - i += 1 - config_dict["Decoys"] = decoys - return config_dict diff --git a/modules/processing/parsers/CAPE/Greame.py b/modules/processing/parsers/CAPE/Greame.py deleted file mode 100644 index 0a7aeb1c128..00000000000 --- a/modules/processing/parsers/CAPE/Greame.py +++ /dev/null @@ -1,90 +0,0 @@ -import string - -import pefile - - -def get_config(data): - try: - pe = pefile.PE(data=data) - rt_string_idx = [entry.id for entry in pe.DIRECTORY_ENTRY_RESOURCE.entries].index(pefile.RESOURCE_TYPE["RT_RCDATA"]) - rt_string_directory = pe.DIRECTORY_ENTRY_RESOURCE.entries[rt_string_idx] - for entry in rt_string_directory.directory.entries: - if str(entry.name) == "GREAME": - data_rva = entry.directory.entries[0].data.struct.OffsetToData - size = entry.directory.entries[0].data.struct.Size - data = pe.get_memory_mapped_image()[data_rva : data_rva + size] - return data.split("####@####") - except Exception: - return None - - -def xor_decode(data): - key = 0xBC - encoded = bytearray(data) - for i in range(len(encoded)): - encoded[i] ^= key - return [x for x in str(encoded) if x in string.printable] - - -def parse_config(raw_config): - if len(raw_config) <= 20: - return None - domains = "" - ports = "" - # Config sections 0 - 19 contain a list of Domains and Ports - for x in range(19): - if len(raw_config[x]) > 1: - domains += xor_decode(raw_config[x]).split(":", 1)[0] - domains += "|" - ports += xor_decode(raw_config[x]).split(":", 2)[1] - ports += "|" - config_dict = { - "Domain": domains[:-1], - "Port": ports[:-1], - "ServerID": xor_decode(raw_config[20]), - "Password": xor_decode(raw_config[21]), - "Install Flag": xor_decode(raw_config[22]), - "Install Directory": xor_decode(raw_config[25]), - "Install File Name": xor_decode(raw_config[26]), - "Active X Startup": xor_decode(raw_config[27]), - "REG Key HKLM": xor_decode(raw_config[28]), - "REG Key HKCU": xor_decode(raw_config[29]), - "Enable Message Box": xor_decode(raw_config[30]), - "Message Box Icon": xor_decode(raw_config[31]), - "Message Box Button": xor_decode(raw_config[32]), - "Install Message Title": xor_decode(raw_config[33]), - "Install Message Box": xor_decode(raw_config[34]).replace("\r\n", " "), - "Activate Keylogger": xor_decode(raw_config[35]), - "Keylogger Backspace = Delete": xor_decode(raw_config[36]), - "Keylogger Enable FTP": xor_decode(raw_config[37]), - "FTP Address": xor_decode(raw_config[38]), - "FTP Directory": xor_decode(raw_config[39]), - "FTP UserName": xor_decode(raw_config[41]), - "FTP Password": xor_decode(raw_config[42]), - "FTP Port": xor_decode(raw_config[43]), - "FTP Interval": xor_decode(raw_config[44]), - "Persistance": xor_decode(raw_config[59]), - "Hide File": xor_decode(raw_config[60]), - "Change Creation Date": xor_decode(raw_config[61]), - "Mutex": xor_decode(raw_config[62]), - "Melt File": xor_decode(raw_config[63]), - "Startup Policies": xor_decode(raw_config[69]), - "USB Spread": xor_decode(raw_config[70]), - "P2P Spread": xor_decode(raw_config[71]), - "Google Chrome Passwords": xor_decode(raw_config[73]), - } - if xor_decode(raw_config[57]) == 0: - config_dict["Process Injection"] = "Disabled" - elif xor_decode(raw_config[57]) == 1: - config_dict["Process Injection"] = "Default Browser" - elif xor_decode(raw_config[57]) == 2: - config_dict["Process Injection"] = xor_decode(raw_config[58]) - else: - config_dict["Process Injection"] = "None" - return config_dict - - -def extract_config(data): - raw_config = get_config(data) - if raw_config: - return parse_config(raw_config) diff --git a/modules/processing/parsers/CAPE/GuLoader.py b/modules/processing/parsers/CAPE/GuLoader.py deleted file mode 100644 index 1d858ac7d6d..00000000000 --- a/modules/processing/parsers/CAPE/GuLoader.py +++ /dev/null @@ -1,17 +0,0 @@ -try: - import re2 as re -except ImportError: - import re - -url_regex = re.compile(rb"http[s]?://(?:[a-zA-Z]|[0-9]|[$-_@.&+]|[!*\(\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+") - - -def extract_config(data): - try: - urls = [url.lower().decode() for url in url_regex.findall(data)] - if urls: - return {"URLs": urls} - except Exception as e: - print(e) - - return None diff --git a/modules/processing/parsers/CAPE/Hancitor.py b/modules/processing/parsers/CAPE/Hancitor.py deleted file mode 100644 index 7cf6a679924..00000000000 --- a/modules/processing/parsers/CAPE/Hancitor.py +++ /dev/null @@ -1,78 +0,0 @@ -""" - Hancitor config extractor -""" - -import hashlib -import logging -import re -import struct - -import pefile -from Cryptodome.Cipher import ARC4 - -DESCRIPTION = "Hancitor config extractor." -AUTHOR = "threathive, cccs-j" - -log = logging.getLogger(__name__) - - -def getHashKey(key_data): - # source: https://github.com/OALabs/Lab-Notes/blob/main/Hancitor/hancitor.ipynb - m = hashlib.sha1() - m.update(key_data) - key = m.digest()[:5] - return key - - -def get_key_config_data(filebuf, pe): - # source: https://github.com/OALabs/Lab-Notes/blob/main/Hancitor/hancitor.ipynb - RE_KEY = rb"\x6a(.)\x68(....)\x68\x00\x20\x00\x00" - m = re.search(RE_KEY, filebuf) - if not m: - return - key_len = struct.unpack("b", m.group(1))[0] - key_address = struct.unpack(". - -DESCRIPTION = "HttpBrowser configuration parser." -AUTHOR = "kevoreilly" - - -import struct - -import pefile -import yara - -rule_source = """ -rule HttpBrowser -{ - meta: - author = "kev" - description = "HttpBrowser C2 connect function" - cape_type = "HttpBrowser Payload" - strings: - $connect_1 = {33 C0 68 06 02 00 00 66 89 ?? ?? ?? ?? ?? 8D ?? ?? ?? ?? ?? 5? 50 E8 ?? ?? 00 00 8B 35 ?? ?? ?? ?? 83 C4 0C 6A 01 BB ?? ?? ?? ?? 53 FF D6 59 50 BF} - $connect_2 = {33 C0 68 06 02 00 00 66 89 ?? ?? ?? 8D ?? ?? ?? 5? 50 E8 ?? ?? 00 00 8B 35 ?? ?? ?? ?? 83 C4 0C 6A 01 BB ?? ?? ?? ?? 53 FF D6 59 50 BF} - $connect_3 = {68 40 1F 00 00 FF 15 ?? ?? ?? ?? 8B 35 ?? ?? ?? ?? BB ?? ?? ?? ?? 53 FF D6 59 50 BF ?? ?? ?? ?? 57 E8 ?? ?? ?? ?? 59 59} - $connect_4 = {33 C0 57 66 89 85 ?? ?? ?? ?? 8D 85 ?? ?? ?? ?? 56 50 E8 ?? ?? ?? ?? 6A 01 FF 75 08 8D 85 ?? ?? ?? ?? 68 ?? ?? ?? ?? 68} - condition: - //check for MZ Signature at offset 0 - uint16(0) == 0x5A4D - - and - - $connect_1 or $connect_2 or $connect_3 or $connect_4 -} -""" - -MAX_STRING_SIZE = 67 - - -def yara_scan(raw_data): - addresses = {} - yara_rules = yara.compile(source=rule_source) - matches = yara_rules.match(data=raw_data) - for match in matches: - if match.rule == "HttpBrowser": - for item in match.strings: - addresses[item.identifier] = item.instances[0].offset - return addresses - - -def pe_data(pe, va, size): - image_base = pe.OPTIONAL_HEADER.ImageBase - rva = va - image_base - return pe.get_data(rva, size) - - -def ascii_from_va(pe, offset): - image_base = pe.OPTIONAL_HEADER.ImageBase - string_rva = struct.unpack("i", pe.__data__[offset : offset + 4])[0] - image_base - string_offset = pe.get_offset_from_rva(string_rva) - return pe.__data__[string_offset : string_offset + MAX_STRING_SIZE].split(b"\0", 1)[0] - - -def unicode_from_va(pe, offset): - image_base = pe.OPTIONAL_HEADER.ImageBase - string_rva = struct.unpack("i", pe.__data__[offset : offset + 4])[0] - image_base - string_offset = pe.get_offset_from_rva(string_rva) - return pe.__data__[string_offset : string_offset + MAX_STRING_SIZE].split(b"\x00\x00", 1)[0] - - -match_map = { - "$connect_1": [39, 49], - "$connect_2": [35, 45], - "$connect_3": [18, 28, 66], - "$connect_4": [35, 90, 13], -} - - -def extract_config(filebuf): - pe = pefile.PE(data=filebuf, fast_load=True) - # image_base = pe.OPTIONAL_HEADER.ImageBase - - yara_matches = yara_scan(filebuf) - tmp_config = {} - for key, values in match_map.keys(): - if yara_matches.get(key): - yara_offset = int(yara_matches[key]) - - if key in ("$connect_1", "$connect_2", "$connect_3"): - port = ascii_from_va(pe, yara_offset + values[0]) - if port: - tmp_config["port"] = [port, "tcp"] - - c2_address = unicode_from_va(pe, yara_offset + values[1]) - if c2_address: - tmp_config.setdefault("c2_address", []).append(c2_address) - - if key == "$connect_3": - c2_address = unicode_from_va(pe, yara_offset + values[2]) - if c2_address: - tmp_config.setdefault("c2_address", []).append(c2_address) - else: - c2_address = unicode_from_va(pe, yara_offset + values[0]) - if c2_address: - tmp_config["c2_address"] = c2_address - - filepath = unicode_from_va(pe, yara_offset + values[1]) - if filepath: - tmp_config["filepath"] = filepath - - injectionprocess = unicode_from_va(pe, yara_offset - values[2]) - if injectionprocess: - tmp_config["injectionprocess"] = injectionprocess - - return tmp_config diff --git a/modules/processing/parsers/CAPE/IcedID.py b/modules/processing/parsers/CAPE/IcedID.py deleted file mode 100644 index 62de3cb5afc..00000000000 --- a/modules/processing/parsers/CAPE/IcedID.py +++ /dev/null @@ -1,81 +0,0 @@ -# Copyright (C) 2019 Kevin O'Reilly (kevoreilly@gmail.com) -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU 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 General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -# -# Updates to handle stage 1 Based on initial work referenced here and modified to work with python3 -# https://sysopfb.github.io/malware,/icedid/2020/04/28/IcedIDs-updated-photoloader.html -# https://gist.github.com/sysopfb/93eb0090ef47c08e4e516cb045b48b96 -# https://www.group-ib.com/blog/icedid - -import logging -import os -import struct - -import pefile -import yara -from Cryptodome.Cipher import ARC4 - -from lib.cuckoo.common.constants import CUCKOO_ROOT - -yara_path = os.path.join(CUCKOO_ROOT, "data", "yara", "CAPE", "IcedID.yar") -with open(yara_path, "r") as yara_rule: - yara_rules = yara.compile(source=yara_rule.read()) - -log = logging.getLogger(__name__) - -DESCRIPTION = "IcedID Stage 2 configuration parser." -AUTHOR = "kevoreilly,threathive,sysopfb" - - -def yara_scan(raw_data): - try: - return yara_rules.match(data=raw_data) - except Exception as e: - print(e) - - -def extract_config(filebuf): - yara_hit = yara_scan(filebuf) - - for hit in yara_hit: - if hit.rule == "IcedID": # can be either a dll or a exe - enc_data = None - try: - pe = pefile.PE(data=filebuf, fast_load=True) - for section in pe.sections: - if section.Name == b".data\x00\x00\x00": - enc_data = section.get_data() - key = enc_data[:8] - enc_config = enc_data[8:592] - decrypted_data = ARC4.new(key).decrypt(enc_config) - config = list(filter(None, decrypted_data.split(b"\x00"))) - return { - "family": "IcedID", - "version": str(struct.unpack("I", decrypted_data[4:8])[0]), - "paths": [{"path": config[1].decode(), "usage": "other"}], - "http": [{"uri": controller[1:].decode()} for controller in config[2:]], - "other": { - "Bot ID": str(struct.unpack("I", decrypted_data[:4])[0]), - }, - } - except Exception as e: - log.error("Error: %s", e) - - return {} - - -if __name__ == "__main__": - import sys - - with open(sys.argv[1], "rb") as f: - print(extract_config(f.read())) diff --git a/modules/processing/parsers/CAPE/IcedIDLoader.py b/modules/processing/parsers/CAPE/IcedIDLoader.py deleted file mode 100644 index a9251d35df2..00000000000 --- a/modules/processing/parsers/CAPE/IcedIDLoader.py +++ /dev/null @@ -1,48 +0,0 @@ -# Copyright (C) 2021 kevoreilly, enzo -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU 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 General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import struct -from contextlib import suppress - -import pefile - - -def extract_config(filebuf): - cfg = {} - pe = None - with suppress(Exception): - pe = pefile.PE(data=filebuf, fast_load=False) - if pe is None: - return - for section in pe.sections: - if section.Name == b".d\x00\x00\x00\x00\x00\x00": - config_section = bytearray(section.get_data()) - dec = [] - for n, x in enumerate(config_section): - k = x ^ config_section[n + 64] - dec.append(k) - if n > 32: - break - campaign, c2 = struct.unpack("I30s", bytes(dec)) - cfg["C2"] = c2.split(b"\00", 1)[0].decode() - cfg["Campaign"] = campaign - return cfg - - -if __name__ == "__main__": - import sys - from pathlib import Path - - data = Path(sys.argv[1]).read_bytes() - print(extract_config(data)) diff --git a/modules/processing/parsers/CAPE/KoiLoader.py b/modules/processing/parsers/CAPE/KoiLoader.py deleted file mode 100644 index 75563816613..00000000000 --- a/modules/processing/parsers/CAPE/KoiLoader.py +++ /dev/null @@ -1,130 +0,0 @@ -import re -import struct -from contextlib import suppress -from itertools import cycle - -import pefile -import yara - -# Hash = b462e3235c7578450b2b56a8aff875a3d99d22f6970a01db3ba98f7ecb6b01a0 - -RULE_SOURCE = """ -rule KoiLoaderResources -{ - meta: - author = "YungBinary" - description = "Find KoiLoader XOR key and payload resource ids" - strings: - $payload_resource = {8D [2] 50 68 [4] E8} - $xor_key_resource = {8D [2] 51 68 [4] E8} - condition: - uint16(0) == 0x5A4D and $payload_resource and $xor_key_resource -} -""" - - -def yara_scan(raw_data): - yara_rules = yara.compile(source=RULE_SOURCE) - matches = yara_rules.match(data=raw_data) - payload_resource_id = None - xor_key_resource_id = None - - for match in matches: - if match.rule != "KoiLoaderResources": - continue - for item in match.strings: - if "$payload_resource" in item.identifier: - payload_offset = item.instances[0].offset - payload_resource_id = struct.unpack("i", raw_data[payload_offset + 5 : payload_offset + 9])[0] - - elif "$xor_key_resource" in item.identifier: - xor_key_offset = item.instances[0].offset - xor_key_resource_id = struct.unpack("i", raw_data[xor_key_offset + 5 : xor_key_offset + 9])[0] - - return (payload_resource_id, xor_key_resource_id) - - -def remove_nulls(buffer, buffer_size): - """ - Modify a buffer removing null bytes - """ - num_nulls = count_nulls(buffer) - result = skip_nth(buffer, num_nulls + 1) - return bytearray(result) - - -def count_nulls(buffer): - """ - Count null separation in a buffer - """ - num_nulls = 0 - idx = 1 - while True: - cur_byte = buffer[idx] - if cur_byte == 0: - num_nulls += 1 - idx += 1 - continue - else: - break - - return num_nulls - - -def skip_nth(buffer, n): - iterable = list(buffer) - yield from (value for index, value in enumerate(iterable) if (index + 1) % n and (index - 1) % n) - - -def find_c2(decoded_buffer): - decoded_buffer = bytearray(skip_nth(decoded_buffer, 2)) - url_regex = re.compile(rb"http[s]?://(?:[a-zA-Z]|[0-9]|[$-_@.&+]|[!*\(\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+") - urls = [url.lower().decode() for url in url_regex.findall(decoded_buffer)] - return urls - - -def xor_data(data, key): - return bytes(c ^ k for c, k in zip(data, cycle(key))) - - -def extract_config(data): - config_dict = {"C2": []} - - xor_key = b"" - encoded_payload = b"" - - payload_resource_id, xor_key_resource_id = yara_scan(data) - - if payload_resource_id is None or xor_key_resource_id is None: - return - - with suppress(Exception): - pe = pefile.PE(data=data) - for entry in pe.DIRECTORY_ENTRY_RESOURCE.entries: - resource_type = pefile.RESOURCE_TYPE.get(entry.struct.Id) - for directory in entry.directory.entries: - for resource in directory.directory.entries: - if resource_type != "RT_RCDATA": - continue - if directory.struct.Id == xor_key_resource_id: - offset = resource.data.struct.OffsetToData - xor_phrase_size = resource.data.struct.Size - xor_key = pe.get_memory_mapped_image()[offset : offset + xor_phrase_size] - elif directory.struct.Id == payload_resource_id: - offset = resource.data.struct.OffsetToData - encoded_payload_size = resource.data.struct.Size - encoded_payload = pe.get_memory_mapped_image()[offset : offset + encoded_payload_size] - - encoded_payload = remove_nulls(encoded_payload, encoded_payload_size) - decoded_payload = xor_data(encoded_payload, xor_key) - - config_dict["C2"] = find_c2(decoded_payload) - - return config_dict - - -if __name__ == "__main__": - import sys - - with open(sys.argv[1], "rb") as f: - print(extract_config(f.read())) diff --git a/modules/processing/parsers/CAPE/Latrodectus.py b/modules/processing/parsers/CAPE/Latrodectus.py deleted file mode 100644 index 32b6315e339..00000000000 --- a/modules/processing/parsers/CAPE/Latrodectus.py +++ /dev/null @@ -1,199 +0,0 @@ -# Copyright (C) 2024 enzok -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU 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 General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - - -import logging -import os -import re -from contextlib import suppress - -import pefile -import yara -from cryptography.hazmat.backends import default_backend -from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes - -from lib.cuckoo.common.constants import CUCKOO_ROOT - -yara_path = os.path.join(CUCKOO_ROOT, "data", "yara", "CAPE", "Latrodectus.yar") -with open(yara_path, "r") as yara_rule: - yara_rules = yara.compile(source=yara_rule.read()) - -log = logging.getLogger(__name__) - -DESCRIPTION = "Latrodectus configuration parser." -AUTHOR = "enzok" - - -def yara_scan(raw_data): - try: - return yara_rules.match(data=raw_data) - except Exception as e: - print(e) - - -def initialize_key_schedule(key: bytes, iv: bytes) -> Cipher: - backend = default_backend() - cipher = Cipher(algorithms.AES(key), modes.CBC(iv), backend=backend) - return cipher - - -def decrypt_with_ctr(cbc_cipher: Cipher, iv: bytes, data: bytes) -> bytes: - key = cbc_cipher.algorithm.key - backend = default_backend() - cipher = Cipher(algorithms.AES(key), modes.CTR(iv), backend=backend) - decryptor = cipher.decryptor() - plaintext = decryptor.update(data) + decryptor.finalize() - return plaintext - - -def decrypt_string_aes(data: bytes, key: bytes) -> bytes: - len_data = int.from_bytes(data[:2], "little") - iv = data[2:18] - data = data[18 : 18 + len_data] - cbc_cipher = initialize_key_schedule(key, iv) - decrypted_data = decrypt_with_ctr(cbc_cipher, iv, data) - return decrypted_data - - -def prng_seed(seed): - sub_expr = (seed + 11865) << 31 | (seed + 11865) >> 1 - expr1 = (sub_expr << 31 | sub_expr >> 1) << 30 & (2**64 - 1) - sub_expr = (expr1 & 0xFFFFFFFF) | (expr1 >> 32) - expr2 = ((sub_expr ^ 0x151D) >> 30) | (4 * (sub_expr ^ 0x151D)) & (2**32 - 1) - return ((expr2 >> 31) | (2 * expr2)) & 0xFFFFFFFF - - -def decrypt_string(data, type): - seed = int.from_bytes(data[:4], "little") & 0xFFFFFFFF - length = (int.from_bytes(data[4:6], "little")) ^ (int.from_bytes(data[:2], "little")) & 0xFFFF - src = data[6:] - result = bytearray() - - for i in range(length): - if type == 1: - seed += 1 - elif type == 2: - seed = prng_seed(seed) - result.append((seed ^ src[i]) & 0xFF) - return result - - -def get_aes_string(data, key): - str_val = "" - with suppress(Exception): - str_val = decrypt_string_aes(data, key).decode("ascii").replace("\00", "") - return str_val - - -def get_string(match, data): - str_val = "" - i = match.start() // 2 - with suppress(Exception): - str_val = decrypt_string(data[i:], 1).decode("ascii").replace("\00", "") - - if not str_val: - with suppress(Exception): - str_val = decrypt_string(data[i:], 2).decode("ascii").replace("\00", "") - - return str_val - - -def fnv_hash(data): - decode = 0x811C9DC5 - for key in data: - decode = 0x1000193 * (decode ^ key) & 0xFFFFFFFF - return decode - - -def extract_config(filebuf): - yara_hit = yara_scan(filebuf) - cfg = {} - - for hit in yara_hit: - rule = hit.rule - if "Latrodectus" in rule: - version = "" - is_aes = False - key = "" - if "AES" in rule: - is_aes = True - - for item in hit.strings: - for instance in item.instances: - if "$version" in item.identifier and not version: - data = instance.matched_data[::-1] - major = int.from_bytes(data[4:5], byteorder="big") - minor = int.from_bytes(data[12:13], byteorder="big") - version = f"{major}.{minor}" - if "$key" in item.identifier: - key = instance.matched_data[4::5] - try: - pe = pefile.PE(data=filebuf, fast_load=True) - data_sections = [s for s in pe.sections if s.Name.find(b".data") != -1] - if not data_sections: - return - data = data_sections[0].get_data() - str_vals = [] - c2 = [] - campaign = "" - rc4_key = "" - - if is_aes and key: - for i in range(len(data)): - str_val = get_aes_string(data[i : i + 256], key) - if str_val and len(str_val) > 2: - str_vals.append(str_val) - else: - hex_pattern = "".join([rf"{byte:02X}" for byte in data[:4]]) - regex = re.compile(hex_pattern.lower()) - matches = regex.finditer(data.hex()) - - for match in matches: - str_val = get_string(match, data) - if str_val and len(str_val) > 2: - str_vals.append(str_val) - - for i in range(len(str_vals) - 1): - val = str_vals[i] - if "/files/" in val: - offset = 1 - if is_aes: - offset += 1 - campaign = str_vals[i + offset] - elif "ERROR" in val: - rc4_key = str_vals[i + 1] - elif "http" in val: - c2.append(val) - - for item in c2: - str_vals.remove(item) - - cfg = { - "C2": c2, - "Group name": campaign, - "Campaign ID": fnv_hash(campaign.encode()), - "Version": version, - "RC4 key": rc4_key, - "Strings": str_vals, - } - except Exception as e: - log.error("Error: %s", e) - return cfg - - -if __name__ == "__main__": - import sys - - with open(sys.argv[1], "rb") as f: - print(extract_config(f.read())) diff --git a/modules/processing/parsers/CAPE/LokiBot.py b/modules/processing/parsers/CAPE/LokiBot.py deleted file mode 100644 index a6ebf1cad96..00000000000 --- a/modules/processing/parsers/CAPE/LokiBot.py +++ /dev/null @@ -1,168 +0,0 @@ -# MIT License -# -# Copyright (c) Jason Reaves - @sysopfb -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in all -# copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. - -import re -import struct -import sys - -import pefile -from Cryptodome.Cipher import DES3 -from Cryptodome.Util.Padding import unpad - -DESCRIPTION = "LokiBot configuration parser." -AUTHOR = "sysopfb" - - -def find_iv(img): - iv = b"" - temp = re.findall(rb"\x68...\x00.{1,10}\x68...\x00\x68...\x00\x68...\x00\x03\xc1", img) - if temp != []: - (addr,) = struct.unpack_from(".) # 6A 08 push 8 - \x59 # 59 pop ecx - \xBE(?P.{4}) # BE D0 88 41 00 mov esi, offset encrypted_data1 - \x8D\xBD.{4} # 8D BD 68 FE FF FF lea edi, [ebp+encrypted_data_list] - \xF3\xA5 # F3 A5 rep movsd - \x6A. # 6A 43 push 43h ; 'C' - \x5B # 5B pop ebx - \x53 # 53 push ebx - \x8D\x85.{4} # 8D 85 89 FE FF FF lea eax, [ebp+var_177] - \xA4 # A4 movsb - \x6A\x00 # 6A 00 push 0 - \x50 # 50 push eax - \xE8.{4} # E8 78 E9 FE FF call about_memset - """, - re.DOTALL | re.VERBOSE, - ) - num_addr_re2 = re.compile( - rb""" - \x6A(?P.) # 6A 08 push 8 - \x59 # 59 pop ecx - \xBE(?P.{4}) # BE F4 88 41 00 mov esi, offset encrypted_data2 - \x8D.{2,5} # 8D BD CC FE FF FF lea edi, [ebp+var_134] - \xF3\xA5 # F3 A5 rep movsd - \x53 # 53 push ebx - \x8D.{2,5} # 8D 85 ED FE FF FF lea eax, [ebp+var_113] - \x6A\x00 # 6A 00 push 0 - \x50 # 50 push eax - \xA4 # A4 movsb - \xE8.{4} # E8 58 E9 FE FF call about_memset - """, - re.DOTALL | re.VERBOSE, - ) - - num_addr_list = re.findall(num_addr_re1, img) - num_addr_list.extend(re.findall(num_addr_re2, img)) - - for num, addr in num_addr_list: - dlen = ord(num) * 4 - (addr,) = struct.unpack_from(" 2: - if not contains_non_printable(line): - config_dict["C2"].append(line) - except Exception: - continue - except Exception: - pass - - # If no C2s with the old method, - # try with newer version xor decoding - if not config_dict["C2"]: - try: - rdata = get_rdata(data) - strings = extract_strings(rdata, 44) - base64_strings = get_base64_strings(strings) - - for base64_str in base64_strings: - try: - decoded_bytes = base64.b64decode(base64_str, validate=True) - encoded_c2 = decoded_bytes[32:] - xor_key = decoded_bytes[:32] - decoded_c2 = xor_data(encoded_c2, xor_key) - - if not contains_non_printable(decoded_c2): - config_dict["C2"].append(decoded_c2.decode()) - except Exception: - continue - except Exception: - return - - return config_dict - - -if __name__ == "__main__": - import sys - - with open(sys.argv[1], "rb") as f: - print(extract_config(f.read())) diff --git a/modules/processing/parsers/CAPE/NanoCore.py b/modules/processing/parsers/CAPE/NanoCore.py deleted file mode 100644 index f8f3912eedd..00000000000 --- a/modules/processing/parsers/CAPE/NanoCore.py +++ /dev/null @@ -1,200 +0,0 @@ -# based on https://github.com/nict-csl/NanoCoreRAT-Analysis.git - -import datetime -import io -import logging -import uuid -import zlib -from contextlib import suppress -from enum import Enum - -import pefile - -HAVE_PYCYPTODOMEX = False -with suppress(ImportError): - from Cryptodome.Cipher import DES - from Cryptodome.Util.Padding import unpad - - HAVE_PYCYPTODOMEX = True - -log = logging.getLogger(__name__) - -DES_KEY = b"\x72\x20\x18\x78\x8c\x29\x48\x97" -DES_IV = DES_KEY - - -class DataType(Enum): - BOOL = 0 - BYTE = 1 - BYTEARRAY = 2 - CHAR = 3 - CHARARRAY = 4 - DECIMAL = 5 - DOUBLE = 6 - INT = 7 - LONG = 8 - SBYTE = 9 - SHORT = 10 - FLOAT = 11 - STRING = 12 - UINT = 13 - ULONG = 14 - USHORT = 15 - DATETIME = 16 - STRINGARRAY = 17 - GUID = 18 - SIZE = 19 - RECTANGLE = 20 - VERSION = 21 - UNKNOWN = 100 - - -def des_decrypt(data): - cipher = DES.new(key=DES_KEY, iv=DES_IV, mode=DES.MODE_CBC) - dec_data = cipher.decrypt(data) - if not dec_data: - return b"" - return unpad(dec_data, DES.block_size) - - -def bool_from_byte(byte): - return byte == b"\x01" - - -def deserialize_datetime(ticks): - base_ticks = 0x489F7FF5F7B58000 # 1970/01/01 00:00:00 - unixtime = (ticks - base_ticks) / 10000000 - try: - return datetime.datetime.fromtimestamp(unixtime) - except ValueError: - return ticks - - -def decode(payload): - payload_len = int.from_bytes(payload[:4], "little") - try: - payload_body = des_decrypt(payload[4 : payload_len + 4]) - except ValueError: - return None - - f = io.BytesIO(payload_body) - compressed_mode = bool_from_byte(f.read(1)) - if compressed_mode: - # data length after raw inflate. - data_len = int.from_bytes(f.read(4), "little") - deflate_data = f.read() - inflate_data = zlib.decompress(deflate_data, wbits=-15) - payload_len = len(inflate_data) - f.close() - f = io.BytesIO(inflate_data) - - flag1 = int.from_bytes(f.read(1), "little") # unknown data - flag2 = int.from_bytes(f.read(1), "little") # unknown data - guid = uuid.UUID(bytes=b"\x00" * 16) - params = [] - - check_guid = bool_from_byte(f.read(1)) - if check_guid: - guid_bytes = f.read(16) - guid = uuid.UUID(bytes_le=guid_bytes) - - position = f.tell() - while payload_len > position: - type_num = int.from_bytes(f.read(1), "little") - data_type = DataType(type_num) - if data_type == DataType.BOOL: - value = bool_from_byte(f.read(1)) - elif data_type == DataType.BYTE: - value = f.read(1) - elif data_type == DataType.BYTEARRAY: - data_len = int.from_bytes(f.read(4), "little") - value = f.read(data_len) - elif data_type in (DataType.INT, DataType.UINT): - value = int.from_bytes(f.read(4), "little") - elif data_type in (DataType.LONG, DataType.ULONG): - value = int.from_bytes(f.read(8), "little") - elif data_type in (DataType.SHORT, DataType.USHORT): - value = int.from_bytes(f.read(2), "little") - elif data_type == DataType.FLOAT: - value = float(int.from_bytes(f.read(4), "little")) - elif data_type in (DataType.STRING, DataType.VERSION): - data_len = int.from_bytes(f.read(1), "little") - value = f.read(data_len).decode() - elif data_type == DataType.DATETIME: - ticks = int.from_bytes(f.read(8), "little") - value = deserialize_datetime(ticks) - elif data_type == DataType.GUID: - value = uuid.UUID(bytes_le=f.read(16)) - else: # TODO: Other Types - data_type = DataType.UNKNOWN - value = f.read() - - if position == f.tell(): - break - position = f.tell() - params.append({"type": data_type, "value": value}) - f.close() - - result = {"uuid": guid, "compressed_mode": compressed_mode, "flags": [flag1, flag2], "params": params} - return result - - -def extract_config(filebuf): - if not HAVE_PYCYPTODOMEX: - log.error("Missed pycryptodomex. Run: poetry install") - return {} - pe = False - with suppress(pefile.PEFormatError, ValueError): - pe = pefile.PE(data=filebuf) - for section in pe.sections: - if b".rsrc" in section.Name: - break - - if not pe: - return - - config_dict = {} - try: - with io.BytesIO(filebuf) as f: - offset = 0x58 # resource section header - f.seek(section.PointerToRawData + offset) - data_len = int.from_bytes(f.read(4), "little") - _guid = f.read(data_len) - enc_data = f.read() - dec_data = decode(enc_data) - - # dec_data to config format - - params = iter(dec_data["params"]) - for param in params: - if DataType.STRING == param["type"]: - item_name = param["value"] - param = next(params) - if DataType.BYTEARRAY == param["type"]: - pass - elif DataType.DATETIME == param["type"]: - dt = param["value"] - config_dict[item_name] = dt.strftime("%Y-%m-%d %H:%M:%S.%f") - else: - config_dict[item_name] = str(param["value"]) - except Exception as e: - log.error("nanocore error: %s", e) - - cncs = [] - - if config_dict.get("PrimaryConnectionHost"): - cncs.append(config_dict["PrimaryConnectionHost"]) - if config_dict.get("PrimaryConnectionHost"): - cncs.append(config_dict["BackupConnectionHost"]) - if config_dict.get("ConnectionPort") and cncs: - port = config_dict["ConnectionPort"] - config_dict["cncs"] = [f"{cnc}:{port}" for cnc in cncs] - return config_dict - - -if __name__ == "__main__": - import sys - from pathlib import Path - - data = Path(sys.argv[1]).read_bytes() - print(extract_config(data)) diff --git a/modules/processing/parsers/CAPE/Nighthawk.py b/modules/processing/parsers/CAPE/Nighthawk.py deleted file mode 100644 index cc6d1d62b90..00000000000 --- a/modules/processing/parsers/CAPE/Nighthawk.py +++ /dev/null @@ -1,356 +0,0 @@ -import gzip -import itertools -import json -import struct - -import pefile -import regex as re -from Cryptodome.Cipher import AES - -DESCRIPTION = "NightHawk C2 DLL configuration parser." -AUTHOR = "Nikhil Ashok Hegde <@ka1do9>, Amjad Alsharafi" - - -def _decode_str(encoded_string, plaintext_alphabet, ciphertext_alphabet): - """ - This function implements the substitution cipher that Nighthawk uses. - Encoded strings are decoded. - Borrowed from https://www.proofpoint.com/us/blog/threat-insight/nighthawk-and-coming-pentest-tool-likely-gain-threat-actor-notice - which is no longer available, but here's an archive link: - https://web.archive.org/web/20221128090619/https://www.proofpoint.com/us/blog/threat-insight/nighthawk-and-coming-pentest-tool-likely-gain-threat-actor-notice - - :param encoded_string: String encoded with Nighthawk substitution cipher - :type encoded_string: - :param plaintext_alphabet: Plaintext alphabet used in the substitution cipher - :type plaintext_alphabet: - :param ciphertext_alphabet: Ciphertext alphabet used in the substitution cipher - :type ciphertext_alphabet: - :return: Decoded string - :rtype: str - """ - - decoded_string_list = [] - - for enc_str in bytes(encoded_string, "utf-8"): - if enc_str in ciphertext_alphabet: - decoded_string_list.append(chr(plaintext_alphabet[ciphertext_alphabet.find(enc_str)])) - else: - decoded_string_list.append(chr(enc_str)) - - return "".join(decoded_string_list) - - -def decode_config_part(item, plaintext_alphabet, ciphertext_alphabet): - """ - This function handles each element type of the NightHawk config. - Encoded strings are decoded. - :param item: config inner item - :type item: any - :param plaintext_alphabet: Plaintext alphabet used in the substitution cipher - :type plaintext_alphabet: - :param ciphertext_alphabet: Ciphertext alphabet used in the substitution cipher - :type ciphertext_alphabet: - :return: same object type as the input, but with decoded strings - :rtype: any - """ - if isinstance(item, dict): - return decode_config_strings(item.copy(), plaintext_alphabet, ciphertext_alphabet) - elif isinstance(item, str): - return _decode_str(item, plaintext_alphabet, ciphertext_alphabet) - elif isinstance(item, list): - newlist = [] - for s in item: - newlist.append(decode_config_part(s, plaintext_alphabet, ciphertext_alphabet)) - return newlist - # pass as is - return item - - -def decode_config_strings(config, plaintext_alphabet, ciphertext_alphabet): - """ - This function implements the substitution cipher that Nighthawk uses. - Encoded strings are decoded. - :param decrypted_config: Decrypted Nighthawk config - :type decrypted_config: dict - :param plaintext_alphabet: Plaintext alphabet used in the substitution cipher - :type plaintext_alphabet: - :param ciphertext_alphabet: Ciphertext alphabet used in the substitution cipher - :type ciphertext_alphabet: - :return: JSON with decoded strings - :rtype: dict - """ - result = {} - for k in config.keys(): - decoded_string = _decode_str(k, plaintext_alphabet, ciphertext_alphabet) - result[decoded_string] = decode_config_part(config[k], plaintext_alphabet, ciphertext_alphabet) - return result - - -def _get_section_data(data, section_name, take_first=True): - """ - Function to return data belonging to `section_name` section in PE `data` - - :param data: Nighthawk DLL contents - :type data: - :param section_name: Name of section whose data is to be retrieved - :type section_name: str - :return: section data - :rtype: or None - """ - - try: - pe = pefile.PE(data=data, fast_load=False) - except Exception: - pe = None - - if not pe: - return None - - data = None - for section in pe.sections: - if section.Name.strip(b"\x00") == section_name: - data = section.get_data() - # if we care about first one, just break, otherwise keep looking for the next section with same name - if take_first: - break - - return data - - -def _alphabet_heuristics(alphabets): - """ - This function implements heuristics to determine if an identified alphabet - string is actually an alphabet. These heuristics are purely based on my - observations. - - :param alpha: Possible alphabet strings - :type alpha: list of - :return: set of possible alphabet bytestrings - :rtype: set of - """ - - candidates = {} - finalists = set() - - for alpha in alphabets: - num_whitespace = len(re.split(rb"\s+", alpha)) - if num_whitespace > 3: - # I've observed alphabets usually have num_whitespace == 2 - continue - - num_unique_chars = len(set(alpha)) - if num_unique_chars < 15: - # I've observed that alphabets have large number of unique characters - # Random low threshold, though - continue - - if num_unique_chars not in candidates: - candidates[num_unique_chars] = set() - candidates[num_unique_chars].add(alpha) - - # I've observed that the plaintext and ciphertext alphabets both have the - # same number of num_unique_chars - for _, alphabets_ in candidates.items(): - if len(alphabets_) > 1: - finalists.update(alphabets_) - - return finalists - - -def get_possible_alphabet(data): - """ - Nighthawk is known to encode strings using a simple substitution cipher. - Decoding requires knowing the plaintext and ciphertext alphabets used. - - :param data: Nighthawk DLL contents - :type data: - :return: Permutation of possible plaintext and ciphertext alphabets - :rtype: or None - """ - - alphabets_regex = rb"[\w\s!\\\"\#\$%\&'\(\)\*\+,\-\./:;<=>\?@\[\]\^_`\{\}\~\|]{86}\x00" - alphabets_regexc = re.compile(alphabets_regex) - - # Alphabets are known to exist in the .rdata section, so just search there - rdata_data = _get_section_data(data, b".rdata") - matches = alphabets_regexc.findall(rdata_data) - - if matches: - alphabets = _alphabet_heuristics(matches) - if alphabets: - # At this point, I have candidate alphabet strings but I don't know - # which is the plaintext alphabet and which is ciphertext alphabet - # To brute force, I'll calculate different permutations of length 2 - return itertools.permutations(alphabets, 2) - - return None - - -def decrypt_config(encrypted_config, decryption_key): - """ - Nighthawk config is gzip compressed and then encrypted with AES-128 CBC mode. - - :param encrypted_config: Encrypted config data - :type encrypted_config: - :param decryption_key: Config decryption key - :type decryption_key: - :return: decrypted config - :rtype: dict or None - """ - - cipher = AES.new(decryption_key, AES.MODE_CBC, IV=16 * b"\x00") - gzip_config = cipher.decrypt(encrypted_config) - - if gzip_config[:2] != b"\x1F\x8B": - # gzip magic signature is b'\x1F\x8B' at offset 0 - return None - - # I've noticed gzip_config containing additional data at the end. - # Below statements truncate gzip_config to the rightmost b'\x00\x00' - # which is gzip end-of-stream marker - i = gzip_config.rindex(b"\x00\x00") - gzip_config = gzip_config[: i + 2] - - config = gzip.decompress(gzip_config).decode("utf-8") - return json.loads(config) - - -def get_encoded_config(profile_section_contents): - """ - The contents of Nighthawk DLL .profile section contain 4 components: - 1. Keying method - 2. Config decryption key (optional) - 2. Size of configuration - 3. Encrypted configuration - - At this point, it is confirmed that the keying method == 0 and config - decryption key is available in the .profile section. - - :param data: Nighthawk DLL .profile section contents - :type data: - :return: Encrypted config data - :rtype: or None - """ - - config_size = struct.unpack(" (len(profile_section_contents) - 1 - 16 - 4): - # max config size == size of .profile section - keying method 1 byte - 16 - # bytes config decryption key - 4 bytes config size field. - # Actual config size cannot be greater than max possible config size - return None - - return profile_section_contents[21 : 21 + config_size] - - -def get_decryption_key(profile_section_contents): - """ - The contents of Nighthawk DLL .profile section contain 4 components: - 1. Keying method - 2. Config decryption key (optional) - 2. Size of configuration - 3. Encrypted configuration - - :param data: Nighthawk DLL .profile section contents - :type data: - :return: Config decryption key - :rtype: or None - """ - - keying_method = profile_section_contents[0] - if keying_method == 0: - # Config decryption key is embedded in .profile section contents - return profile_section_contents[1:17] - - return None - - -def get_profile_section_contents(data): - """ - Nighthawk DLLs are known to contain a .profile section which contains - configuration information. - - :param data: Nighthawk DLL contents - :type data: - :return: .profile section contents - :rtype: or None - """ - - return _get_section_data(data, b".profile") - - -def get_last_text_section(data): - """ - Newer Nighthawk DLLs are known to contain a .text at the end which contains - configuration information. - - :param data: Nighthawk DLL contents - :type data: - :return: last .text section contents - :rtype: or None - """ - - return _get_section_data(data, b".text", take_first=False) - - -def get_config_section_content(data): - """ - Get the config section data either from .profile, or from the last .text section - which is available - - :param data: Nighthawk DLL contents - :type data: - :return: the config data contents - :rtype: or None - """ - - return get_profile_section_contents(data) or get_last_text_section(data) - - -def extract_config(data): - """ - Configuration extractor for Nighthawk DLL - - :param data: Nighthawk DLL contents - :type data: - :return: Decrypted and decoded config - :rtype: dict or None - """ - - # Will contain the final config that is passed to CAPEv2 - cfg = {} - - profile_section_contents = get_config_section_content(data) - if profile_section_contents is None: - return None - - decryption_key = get_decryption_key(profile_section_contents) - if decryption_key is None: - return None - - config = get_encoded_config(profile_section_contents) - - decrypted_config = decrypt_config(config, decryption_key) - - # decrypt_config is the decrypted configuration, but key and values strings - # are still encoded and need to be decoded. Nighthawk is known to encode - # strings using a simple substitution cipher. The real challenge is to extract - # the ciphertext and plaintext alphabet from the DLL - - possible_alphabets = get_possible_alphabet(data) - - for plaintext_alphabet, ciphertext_alphabet in possible_alphabets: - config_ = decode_config_strings( - decrypted_config, - plaintext_alphabet, - ciphertext_alphabet, - ) - - if "implant-config" in config_: - # This is a heuristic and may fail in future versions - cfg["Plaintext Alphabet"] = plaintext_alphabet - cfg["Ciphertext Alphabet"] = ciphertext_alphabet - cfg["Config AES-128 CBC Decryption Key"] = decryption_key - cfg["Implant Config"] = config_ - break - - return cfg diff --git a/modules/processing/parsers/CAPE/Njrat.py b/modules/processing/parsers/CAPE/Njrat.py deleted file mode 100644 index 27fa080e26e..00000000000 --- a/modules/processing/parsers/CAPE/Njrat.py +++ /dev/null @@ -1,193 +0,0 @@ -import base64 -import re -import sys -from contextlib import suppress - -import dnfile - - -class Parser: - def __init__(self, data: bytes): - self.dotnet_file = dnfile.dnPE(data=data) - - # ex: 72 9F 00 00 70 ldstr foo, the index is what comes after 0x72 opcode -> 0x9F - def get_user_string_from_index(self, index): - return self.dotnet_file.net.user_strings.get(index).value - - # in little-endian token is: 12 00 00 04 (0x40000012), where 0x04 is field table index, and 0x12 is the field index - def get_field_name_from_index(self, index): - return self.dotnet_file.net.mdtables.Field.get_with_row_index(index).Name - - def close(self): - self.dotnet_file.close() - - -CONFIG_MAPPING = { - "DR": "directory", - "EXE": "executable", - "H": "domain", - "P": "port", - "VN": "campaign_id", - "VR": "version", - "RG": "registry_value", - "x": "port", - "ss": "domain", -} - -REPLACES_MAPPING = { - "विनी": "M", - "蒂": "T", - "मे": "A", - "बीपी": "Z", - "粹": "M", - "ता": "T", - "의도": "A", - "에": "e", - "!": "=", - "FRANSESCO": "M", - "Strik": "=", -} - - -def get_patterns(): - # ldstr, stsfld - pattern_1 = re.compile( - Rb"""(?x) - \x72(...)\x70 - \x80(...)\x04 - """ - ) - - # ldstr, call Conversions.ToBoolean, stsfld - pattern_2 = re.compile( - Rb"""(?x) - \x72(...)\x70 - \x28\x04\x00\x00\x0A - \x80(...)\x04 - """ - ) - - return [pattern_1, pattern_2] - - -def get_matches(data, patterns): - matches = [] - - for pattern in patterns: - matches.extend(pattern.findall(data)) - - return matches - - -def get_config_dict(parser, data): - patterns = get_patterns() - matches = get_matches(data, patterns) - - if matches: - - config_dict = {} - - for match in matches: - string_index = int.from_bytes(match[0], "little") - field_index = int.from_bytes(match[1], "little") - - # get each string variable name and value - field_name = parser.get_field_name_from_index(field_index).__str__() - field_value = parser.get_user_string_from_index(string_index).__str__() - config_dict[field_name] = field_value - - return config_dict - - -def normalize_config(config_dict): - normalized_config_dict = {} - - # get only the interesting configs and normalize names - for key in config_dict: - if key in CONFIG_MAPPING: - normalized_key = CONFIG_MAPPING[key] - normalized_config_dict[normalized_key] = config_dict[key] - - return normalized_config_dict - - -def decode_b64_values(config): - if "campaign_id" in config: - config["campaign_id"] = base64.b64decode(config["campaign_id"]).decode() - - return config - - -def do_string_replaces(s): - for key in REPLACES_MAPPING: - if key in s: - s = s.replace(key, REPLACES_MAPPING[key]) - - return s - - -def replaces_and_b6d_decode(config): - clean_domain = do_string_replaces(config["domain"]) - clean_port = do_string_replaces(config["port"]) - - config["domain"] = base64.b64decode(clean_domain).decode() - config["port"] = base64.b64decode(clean_port).decode() - - return config - - -def clean_https_reversed_port_and_domain(config): - if "https" in config["port"]: - config["port"] = config["port"].replace("https://", "")[::-1] - config["domain"] = config["domain"].replace("https://", "")[::-1] - - return config - - -def decode_domain_and_port(config): - try: - if "port" in config and int(config["port"]): - pass - except ValueError: - config = replaces_and_b6d_decode(config) - - return config - - -def decode_reversed_ss_and_x(config): - return config - - -def get_clean_config(config_dict): - with suppress(Exception): - config = normalize_config(config_dict) - config = decode_b64_values(config) - config = clean_https_reversed_port_and_domain(config) - config = decode_domain_and_port(config) - config = decode_reversed_ss_and_x(config) - - return config - - -def extract_config(data): - conf = {} - dotnet_file_parser = Parser(data=data) - config_dict = get_config_dict(dotnet_file_parser, data) - config = get_clean_config(config_dict) - - if config.get("domain") and config.get("port"): - conf["cncs"] = [f"{config['domain']}:{config['port']}"] - - if config.get("campaign_id"): - conf["campaign id"] = config["campaign_id"] - - if config.get("version"): - conf["version"] = config["version"] - - dotnet_file_parser.close() - return conf - - -if "__main__" == __name__: - with open(sys.argv[1], "rb") as f: - print(extract_config(f.read())) diff --git a/modules/processing/parsers/CAPE/Oyster.py b/modules/processing/parsers/CAPE/Oyster.py deleted file mode 100644 index 4d328529852..00000000000 --- a/modules/processing/parsers/CAPE/Oyster.py +++ /dev/null @@ -1,126 +0,0 @@ -# Copyright (C) 2024 enzok -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU 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 General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - - -import logging -import os -import re -import struct -from contextlib import suppress - -import pefile -import yara - -from lib.cuckoo.common.constants import CUCKOO_ROOT - -yara_path = os.path.join(CUCKOO_ROOT, "data", "yara", "CAPE", "Oyster.yar") -if not os.path.exists(yara_path): - yara_path = os.path.join(CUCKOO_ROOT, "custom", "yara", "CAPE", "Oyster.yar") - -with open(yara_path, "r") as yara_rule: - yara_rules = yara.compile(source=yara_rule.read()) - -log = logging.getLogger(__name__) - -DESCRIPTION = "Oyster configuration parser." -AUTHOR = "enzok" - - -def transform(src, lookup_table): - length = len(src) - i = 0 - num = length // 2 - if num > 0: - pVal = length - 1 - while i < num: - k = src[pVal] - n = src[i] - src[i] = lookup_table[k] - i += 1 - result = lookup_table[n] - src[pVal] = result - pVal -= 1 - return src - - -def yara_scan(raw_data): - try: - return yara_rules.match(data=raw_data) - except Exception as e: - print(e) - - -def extract_config(filebuf): - yara_hit = yara_scan(filebuf) - cfg = {} - - for hit in yara_hit: - if hit.rule == "Oyster": - start_offset = "" - lookup_va = "" - for item in hit.strings: - if "$start_exit" == item.identifier: - start_offset = item.instances[0].offset - if "$decode" == item.identifier: - decode_offset = item.instances[0].offset - lookup_va = filebuf[decode_offset + 12 : decode_offset + 16] - if not (start_offset and lookup_va): - return - try: - pe = pefile.PE(data=filebuf, fast_load=True) - lookup_offset = pe.get_offset_from_rva(struct.unpack("I", lookup_va)[0] - pe.OPTIONAL_HEADER.ImageBase) - lookup_table = filebuf[lookup_offset : lookup_offset + 256] - data = filebuf[start_offset + 4 : start_offset + 8092] - hex_strings = re.split(rb"\x00+", data) - hex_strings = [s for s in hex_strings if s] - str_vals = [] - c2 = [] - dll_version = "" - - c2_pattern = r"\b[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*\.(?!txt\b|dll\b|exe\b)[a-zA-Z]{2,}" - - for item in hex_strings: - with suppress(Exception): - decoded = transform(bytearray(item), bytearray(lookup_table)).decode("utf-8") - if not decoded: - continue - if "http" in decoded: - if "\r\n" in decoded: - c2.extend(list(filter(None, decoded.split("\r\n")))) - else: - c2.append(decoded) - elif "dll_version" in decoded: - dll_version = decoded.split('":"')[-1] - elif "api" in decoded or "Content-Type" in decoded: - str_vals.append(decoded) - else: - c2_matches = re.findall(c2_pattern, decoded) - if c2_matches: - c2.extend(c2_matches) - - cfg = { - "C2": c2, - "Dll Version": dll_version, - "Strings": str_vals, - } - except Exception as e: - log.error("Error: %s", e) - return cfg - - -if __name__ == "__main__": - import sys - - with open(sys.argv[1], "rb") as f: - print(extract_config(f.read())) diff --git a/modules/processing/parsers/CAPE/Pandora.py b/modules/processing/parsers/CAPE/Pandora.py deleted file mode 100644 index 637d844312d..00000000000 --- a/modules/processing/parsers/CAPE/Pandora.py +++ /dev/null @@ -1,77 +0,0 @@ -import pefile - - -def version_21(raw_config): - if raw_config is None: - return None - return { - "Version": "2.1", - "Domain": raw_config[0], - "Port": raw_config[1], - "Password": raw_config[2], - "Install Path": raw_config[3], - "Install Name": raw_config[4], - "HKCU Key": raw_config[5], - "ActiveX Key": raw_config[6], - "Install Flag": raw_config[7], - "StartupFlag": raw_config[8], - "ActiveXFlag": raw_config[9], - "HKCU Flag": raw_config[10], - "Mutex": raw_config[11], - "userMode Hooking": raw_config[12], - "Melt": raw_config[13], - "Keylogger": raw_config[14], - "Campaign ID": raw_config[15], - "UnknownFlag9": raw_config[16], - } - - -def version_22(raw_config): - if raw_config is None: - return None - return { - "Version": "2.2", - "Domain": raw_config[0], - "Port": raw_config[1], - "Password": raw_config[2], - "Install Path": raw_config[3], - "Install Name": raw_config[4], - "HKCU Key": raw_config[5], - "ActiveX Key": raw_config[6], - "Install Flag": raw_config[7], - "StartupFlag": raw_config[8], - "ActiveXFlag": raw_config[9], - "HKCU Flag": raw_config[10], - "Mutex": raw_config[11], - "userMode Hooking": raw_config[12], - "Melt": raw_config[13], - "Keylogger": raw_config[14], - "Campaign ID": raw_config[15], - "UnknownFlag9": raw_config[16], - } - - -def get_config(data): - try: - pe = pefile.PE(data=data) - rt_string_idx = [entry.id for entry in pe.DIRECTORY_ENTRY_RESOURCE.entries].index(pefile.RESOURCE_TYPE["RT_RCDATA"]) - rt_string_directory = pe.DIRECTORY_ENTRY_RESOURCE.entries[rt_string_idx] - for entry in rt_string_directory.directory.entries: - if str(entry.name) == "CFG": - data_rva = entry.directory.entries[0].data.struct.OffsetToData - size = entry.directory.entries[0].data.struct.Size - data = pe.get_memory_mapped_image()[data_rva : data_rva + size] - cleaned = data.replace("\x00", "") - return cleaned.split("##") - except Exception: - return - - -def extract_config(data): - raw_config = get_config(data) - if raw_config: - if len(raw_config) == 19: - clean_config = version_21(raw_config) - elif len(raw_config) == 20: - clean_config = version_22(raw_config) - return clean_config diff --git a/modules/processing/parsers/CAPE/PhemedroneStealer.py b/modules/processing/parsers/CAPE/PhemedroneStealer.py deleted file mode 100644 index 19018b83536..00000000000 --- a/modules/processing/parsers/CAPE/PhemedroneStealer.py +++ /dev/null @@ -1,191 +0,0 @@ -# Phemedrone Stealer config extractor by @tccontre18 - Br3akp0int -# https://github.com/tccontre/KnowledgeBase/blob/main/malware_re_tools/phemdrone_cfg_extractor/phemdrone_extractor_s.py - -import abc - -CilMethodBodyReaderBase = abc.ABC - -try: - import dnfile - from dnfile.enums import MetadataTables - - HAVE_DNFILE = True -except ImportError: - HAVE_DNFILE = False - -try: - from dncil.cil.body import CilMethodBody - from dncil.cil.body.reader import CilMethodBodyReaderBase - from dncil.cil.error import MethodBodyFormatError - from dncil.clr.token import InvalidToken, StringToken, Token - - HAVE_DNCIL = True -except ImportError: - print("Missed dependency: poetry run pip install dncil") - HAVE_DNCIL = False - - -class DnfileMethodBodyReader(CilMethodBodyReaderBase): - def __init__(self, pe, row): - """ """ - self.pe = pe - self.offset = self.pe.get_offset_from_rva(row.Rva) - - def read(self, n): - """ """ - data = self.pe.get_data(self.pe.get_rva_from_offset(self.offset), n) - self.offset += n - return data - - def tell(self): - """ """ - return self.offset - - def seek(self, offset): - """ """ - self.offset = offset - return self.offset - - -class DnfileParse: - DOTNET_META_TABLES_BY_INDEX = {table.value: table.name for table in MetadataTables} - - @staticmethod - def read_dotnet_user_string(pe, token): - """read user string from #US stream""" - try: - user_string = pe.net.user_strings.get(token.rid) - except UnicodeDecodeError: - return InvalidToken(token.value) - - if user_string is None: - return InvalidToken(token.value) - - return user_string.value - - @staticmethod - def resolve_token(pe, token): - """ """ - if isinstance(token, StringToken): - return DnfileParse.read_dotnet_user_string(pe, token) - - table_name = DnfileParse.DOTNET_META_TABLES_BY_INDEX.get(token.table, "") - if not table_name: - # table_index is not valid - return InvalidToken(token.value) - - table = getattr(pe.net.mdtables, table_name, None) - if table is None: - # table index is valid but table is not present - return InvalidToken(token.value) - - try: - return table.rows[token.rid - 1] - except IndexError: - # table index is valid but row index is not valid - return InvalidToken(token.value) - - @staticmethod - def read_method_body(pe, row): - """ """ - return CilMethodBody(DnfileMethodBodyReader(pe, row)) - - @staticmethod - def format_operand(pe, operand): - """ """ - if isinstance(operand, Token): - operand = DnfileParse.resolve_token(pe, operand) - - if isinstance(operand, str): - return f'"{operand}"' - elif isinstance(operand, int): - return hex(operand) - elif isinstance(operand, list): - return f"[{', '.join(['({:04X})'.format(x) for x in operand])}]" - elif isinstance(operand, dnfile.mdtable.MemberRefRow): - if isinstance(operand.Class.row, (dnfile.mdtable.TypeRefRow,)): - return f"{str(operand.Class.row.TypeNamespace)}.{operand.Class.row.TypeName}::{operand.Name}" - elif isinstance(operand, dnfile.mdtable.TypeRefRow): - return f"{str(operand.TypeNamespace)}.{operand.TypeName}" - elif isinstance(operand, (dnfile.mdtable.FieldRow, dnfile.mdtable.MethodDefRow)): - return f"{operand.Name}" - elif operand is None: - return "" - - return str(operand) - - @staticmethod - def get_instruction_text(pe, insn): - return ( - "{:04X}".format(insn.offset) - + " " - + f"{' '.join('{:02x}'.format(b) for b in insn.get_bytes()) : <20}" - + f"{str(insn.opcode) : <15}" - + DnfileParse.format_operand(pe, insn.operand) - ) - - -def check_next_inst(pe, body, DnfileParse, index): - - str_list = [] - for i in range(1, len(body.instructions) << 2): - if index + i >= len(body.instructions): - break - return None - else: - next_inst = body.instructions[index + i] - next_inst_ = DnfileParse.get_instruction_text(pe, next_inst) - if str(next_inst.opcode) == "ldstr": - str_list.append(DnfileParse.resolve_token(pe, next_inst.operand)) - elif str(next_inst.opcode) == "stsfld": - return (next_inst_.split(" ")[-1]), str_list - - -def extract_config(data): - config_dict = {} - if not HAVE_DNFILE or not HAVE_DNCIL: - return - try: - pe = dnfile.dnPE(data=data) - except dnfile.PEFormatError: - return - for row in pe.net.mdtables.MethodDef: - # skip methods that do not have a method body - if not row.ImplFlags.miIL or any((row.Flags.mdAbstract, row.Flags.mdPinvokeImpl)): - continue - try: - body = DnfileParse.read_method_body(pe, row) - except MethodBodyFormatError: - continue - if not body.instructions: - continue - if row.Name == ".cctor": - index = 0 - if len(body.instructions) >= 20 and str(body.instructions[0].opcode) == "ldstr": - for index in range(0, len(body.instructions)): - value_data = "" - config_field_name = "" - inst = body.instructions[index] - inst_ = DnfileParse.get_instruction_text(pe, inst) - if str(inst.opcode) == "ldstr": - value_data = DnfileParse.resolve_token(pe, inst.operand) - config_field_name, str_list = check_next_inst(pe, body, DnfileParse, index) - if config_field_name is not None and config_field_name not in config_dict: - str_list.insert(0, value_data) - config_dict[config_field_name] = ", ".join(str_list) - else: - pass - if "ldc.i4." in str(inst.opcode): - if inst_.split(".")[-1].strip() == "0": - value_data = "False" - config_field_name, str_list = check_next_inst(pe, body, DnfileParse, index) - config_dict[config_field_name] = value_data - elif inst_.split(".")[-1].strip() == "1": - value_data = "True" - config_field_name, str_list = check_next_inst(pe, body, DnfileParse, index) - config_dict[config_field_name] = value_data - else: - value_data = inst_.split(".")[-1].strip() - config_field_name, str_list = check_next_inst(pe, body, DnfileParse, index) - config_dict[config_field_name] = value_data - return config_dict diff --git a/modules/processing/parsers/CAPE/PikaBot.py b/modules/processing/parsers/CAPE/PikaBot.py deleted file mode 100644 index 0ab670fb3a8..00000000000 --- a/modules/processing/parsers/CAPE/PikaBot.py +++ /dev/null @@ -1,186 +0,0 @@ -import base64 -import logging -import re -import struct -from contextlib import suppress -from io import BytesIO - -import pefile -import yara - -rule_source = """ -rule PikaBot -{ - meta: - author = "enzo" - description = "Pikabot config extraction" - packed = "" - strings: - $config = {C7 44 24 [3] 00 00 C7 44 24 [4] 00 89 [1-4] ?? E8 [4] 31 C0 C7 44 24 [3] 00 00 89 44 24 ?? C7 04 24 [4] E8} - condition: - uint16(0) == 0x5A4D and all of them -} -""" - -yara_rules = yara.compile(source=rule_source) - -log = logging.getLogger(__name__) - - -class PikaException(Exception): - pass - - -def yara_scan(raw_data): - try: - return yara_rules.match(data=raw_data) - except Exception as e: - print(e) - - -def xor(data, key): - return bytes([c ^ key for c in data]) - - -def wide_finder(data): - str_end = len(data) - for i in range(0, len(data) - 1, 2): - if not chr(data[i]).isascii(): - str_end = i - break - if data[i + 1] != 0: - str_end = i - break - return data[:str_end] - - -def get_url(ps_string): - out = None - m = re.search(r"http[^ ]*", ps_string) - if m: - out = m.group() - return out - - -def get_wchar_string(data, length): - data = data.read(length) - return data.decode("utf-16-le") - - -def get_strings(data, count): - w_strings = [] - for _ in range(count): - length = struct.unpack("I", data.read(4))[0] - w_string = get_wchar_string(data, length) - w_strings.append(w_string) - return w_strings - - -def get_c2s(data, count): - c2_list = [] - for _ in range(count): - c2_size = struct.unpack("I", data.read(4))[0] - c2 = get_wchar_string(data, c2_size) - port, val1, val2 = struct.unpack("III", data.read(12)) - c2_list.append(f"{c2}:{port}") - return c2_list - - -def get_config(input_data): - data = BytesIO(input_data) - rounds, config_size, _, version_size = struct.unpack("=IIBI", data.read(13)) - version = get_wchar_string(data, version_size) - campaign_size = struct.unpack("I", data.read(4))[0] - campaign_name = get_wchar_string(data, campaign_size) - registry_key_size = struct.unpack("I", data.read(4))[0] - registry_key = get_wchar_string(data, registry_key_size) - user_agent_size = struct.unpack("I", data.read(4))[0] - user_agent = get_wchar_string(data, user_agent_size) - number_of_http_headers = struct.unpack("I", data.read(4))[0] - get_strings(data, number_of_http_headers) - number_of_api_cmds = struct.unpack("I", data.read(4))[0] - get_strings(data, number_of_api_cmds) - number_of_c2s = struct.unpack("I", data.read(4))[0] - c2s = get_c2s(data, number_of_c2s) - - return { - "Version": version, - "Campaign Name": campaign_name, - "Registry Key": registry_key, - "User Agent": user_agent, - # "request_headers": request_headers, - # "api_cmds": api_cmds, - "C2s": c2s, - } - - -def extract_config(filebuf): - pe = None - with suppress(Exception): - pe = pefile.PE(data=filebuf, fast_load=False) - - if not pe: - return - - r_data = None - data = None - - r_data_sections = [s for s in pe.sections if s.Name.find(b".rdata") != -1] - if r_data_sections: - r_data = r_data_sections[0].get_data() - - data_sections = [s for s in pe.sections if s.Name.find(b".data") != -1] - if data_sections: - data = data_sections[0].get_data() - - if r_data: - big_null = r_data.find(b"\x00" * 30) - r_data = r_data[:big_null] - out = None - - for i in range(1, 0xFF): - egg = bytes([i]) * 16 - if egg in r_data: - test_out = xor(r_data, i) - # This might break if the extra crud on the end of the blob is not b64 friendly - try: - test_out_ptxt = base64.b64decode(test_out) - except Exception: - continue - if "http".encode("utf-16le") in test_out_ptxt: - out = wide_finder(test_out_ptxt).decode("utf-16le") - if out: - url = get_url(out) - return {"C2": [url], "PowerShell": out} - - if data: - yara_hit = yara_scan(filebuf) - cfg_va = None - cfg_offset = None - cfg_length = 0 - - for hit in yara_hit: - if hit.rule == "PikaBot": - for item in hit.strings: - if "$config" == item.identifier: - offset = item.instances[0].offset - cfg_va = filebuf[offset + 12 : offset + 16] - with suppress(Exception): - pe = pefile.PE(data=filebuf, fast_load=True) - cfg_offset = pe.get_offset_from_rva(struct.unpack("I", cfg_va)[0] - pe.OPTIONAL_HEADER.ImageBase) - cfg_length = struct.unpack("H", filebuf[offset + 4 : offset + 6])[0] - break - - if cfg_offset: - data = filebuf[cfg_offset : cfg_offset + cfg_length] - if data[4:8] == b"\x00\x00\x00\x00": - return - with suppress(Exception): - config = get_config(data) - return config - - -if __name__ == "__main__": - import sys - - print(extract_config(sys.argv[1])) diff --git a/modules/processing/parsers/CAPE/PlugX.py b/modules/processing/parsers/CAPE/PlugX.py deleted file mode 100644 index 098c04097e3..00000000000 --- a/modules/processing/parsers/CAPE/PlugX.py +++ /dev/null @@ -1,325 +0,0 @@ -# PlugX config parser for CAPE -# -# Based on PlugX RAT detection and analysis for Volatility 2.0, version 1.2 -# -# Author: Fabien Perigaud -# -# Modified for CAPE by Kevin O'Reilly -# -# This plugin is based on poisonivy.py by Andreas Schuster. -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 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 -# General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -import socket -from collections import OrderedDict, defaultdict -from socket import inet_ntoa -from struct import calcsize, unpack_from - -persistence = defaultdict(lambda: "Unknown", {0: "Service + Run Key", 1: "Service", 2: "Run key", 3: "None"}) -regs = defaultdict( - lambda: "Unknown", - { - 0x80000000: "HKEY_CLASSES_ROOT", - 0x80000001: "HKEY_CURRENT_USER", - 0x80000002: "HKEY_LOCAL_MACHINE", - 0x80000003: "HKEY_USERS", - 0x80000005: "HKEY_CURRENT_CONFIG", - }, -) - - -def get_str_utf16le(buff): - tstrend = buff.find(b"\x00\x00") - tstr = buff[: tstrend + (tstrend & 1)] - return tstr.decode() - - -def get_proto(proto): - ret = [] - if proto & 0x1: - ret.append("TCP") - if proto & 0x2: - ret.append("HTTP") - if proto & 0x4: - ret.append("UDP") - if proto & 0x8: - ret.append("ICMP") - if proto & 0x10: - ret.append("DNS") - if proto > 0x1F: - ret.append("OTHER_UNKNOWN") - return " / ".join(ret) - - -def get_proto2(proto): - protos = ("???", "???", "????", "TCP", "HTTP", "DNS", "UDP", "ICMP", "RAW", "???", "???") - try: - ret = protos[proto] + f"({proto})" - except Exception: - ret = f"UNKNOWN ({proto})" - return ret - - -def get_timer_string(timer: tuple) -> str: - timer_str = "" - if timer[0] != 0: - timer_str += f"{timer[0]} days, " - if timer[1] != 0: - timer_str += f"{timer[1]} hours, " - if timer[2] != 0: - timer_str += f"{timer[2]} mins, " - timer_str += f"{timer[3]} secs" - return timer_str - - -def extract_config(cfg_blob): - cfg_sz = len(cfg_blob) - config_output = OrderedDict() - if cfg_sz not in (0xBE4, 0x150C, 0x1510, 0x170C, 0x1B18, 0x1D18, 0x2540, 0x254C, 0x2D58, 0x36A4, 0x4EA4): - return None - if cfg_sz == 0x1510: - cfg_blob = cfg_blob[12:] - elif cfg_sz in (0x36A4, 0x4EA4): - cfg_blob = cfg_blob - else: - cfg_blob = cfg_blob[8:] - # Flags - if cfg_sz == 0xBE4: - desc = " 0 and str(url) != "HTTP://": - url_list.append(str(url)) - if url_list: - config_output.update({"URL": url_list}) - # Proxies - proxy_list = [] - proxy_creds = [] - for _ in range(4): - ptype, port, proxy, user, passwd = unpack_from("<2H64s64s64s", cfg_blob) - cfg_blob = cfg_blob[calcsize("<2H64s64s64s") :] - if proxy[0] != "\x00": - proxy_list.append("{}:{}".format(proxy.split(b"\x00", 1)[0].decode(), port)) - if user[0] != b"\x00": - proxy_creds.append(f"{user.decode()} / {passwd.decode()}\0") - if proxy_list: - config_output.update({"Proxy": proxy_list}) - if proxy_creds: - config_output.update({"Proxy credentials": proxy_creds}) - str_sz = 0x80 if cfg_sz == 0xBE4 else 0x200 - # Persistence - if cfg_sz in (0x1B18, 0x1D18, 0x2540, 0x254C, 0x2D58, 0x36A4, 0x4EA4): - persistence_type = unpack_from("I", data[c2_offset + 1 : c2_offset + 5])[0])) - port = str(struct.unpack(">H", data[c2_offset + 5 : c2_offset + 7])[0]) - controllers.append(f"{ip}:{port}") - return controllers - - -def parse_binary_c2_2(data): - """ - Parses the binary CNC block format introduced April'21 - """ - expected_sha1 = data[:0x14] - data = data[0x14:] - actual_sha1 = hashlib.sha1(data).digest() - - if actual_sha1 != expected_sha1: - log.error("Expected sha1: %s actual: %s", expected_sha1, actual_sha1) - return - - length = len(data) - - controllers = [] - alignment = 0 - if len(data) % 7 == 0: - alignment = 7 - elif len(data) % 8 == 0: - alignment = 8 - - if not alignment: - return controllers - - for c2_offset in range(0, length, alignment): - ip = socket.inet_ntoa(struct.pack("!L", struct.unpack(">I", data[c2_offset + 1 : c2_offset + 5])[0])) - port = str(struct.unpack(">H", data[c2_offset + 5 : c2_offset + 7])[0]) - controllers.append(f"{ip}:{port}") - return controllers - - -def decompress(data): - """ - Decompress data with blzpack decompression - """ - if not HAVE_BLZPACK: - return - return blzpack.decompress_data(BRIEFLZ_HEADER.join(data.split(QAKBOT_HEADER))) - - -def decrypt_data(data): - """ - Decrypts the data using the last 20 bytes as a rc4 key. - Validates the decryption with the sha1 sum contained within the first 20 bytes of the decrypted data. - """ - if not data: - return - - key = data[:0x14] - decrypted_data = ARC4.new(key).decrypt(data[0x14:]) - - if not decrypted_data: - return - - if hashlib.sha1(decrypted_data[0x14:]).digest() != decrypted_data[:0x14]: - return - - return decrypted_data[0x14:] - - -def decrypt_data2(data): - if not data: - return - - hash_obj = hashlib.sha1(b"\\System32\\WindowsPowerShell\\v1.0\\powershell.exe") - rc4_key = hash_obj.digest() - decrypted_data = ARC4.new(rc4_key).decrypt(data) - - if not decrypted_data: - return - - return decrypted_data - - -def decrypt_data3(data): - if not data: - return - - hash_obj = hashlib.sha1(b"\\System32\\WindowsPowerShel1\\v1.0\\powershel1.exe") - rc4_key = hash_obj.digest() - decrypted_data = ARC4.new(rc4_key).decrypt(data) - - if not decrypted_data: - return - - if hashlib.sha1(decrypted_data[0x14:]).digest() == decrypted_data[:0x14]: - return decrypted_data - - # From around 403.902 onwards (30-09-2022) - hash_obj = hashlib.sha1(b"Muhcu#YgcdXubYBu2@2ub4fbUhuiNhyVtcd") - rc4_key = hash_obj.digest() - decrypted_data = ARC4.new(rc4_key).decrypt(data) - - if not decrypted_data: - return - - if rc4_key == decrypted_data[:0x14]: - return decrypted_data - - decrypted_data = ARC4.new(decrypted_data[0x14:0x28]).decrypt(decrypted_data[0x28:]) - if not decrypted_data: - return - - if hashlib.sha1(decrypted_data[0x14:]).digest() != decrypted_data[:0x14]: - return - - return decrypted_data - - -def decrypt_data4(data): - if not data: - return - - hash_obj = hashlib.sha1(b"bUdiuy81gYguty@4frdRdpfko(eKmudeuMncueaN") - rc4_key = hash_obj.digest() - decrypted_data = ARC4.new(rc4_key).decrypt(data) - - if not decrypted_data: - return - - decrypted_data = ARC4.new(decrypted_data[0x14:0x28]).decrypt(decrypted_data[0x28:]) - if not decrypted_data: - return - - if hashlib.sha1(decrypted_data[0x14:]).digest() != decrypted_data[:0x14]: - return - - return decrypted_data - - -def get_sha256_hash(data): - sha256 = SHA256.new() - sha256.update(data) - return sha256.digest() - - -def decrypt_aes_cbc(encrypted_data, key, iv): - decoded = "" - with suppress(Exception): - cipher = AES.new(key, AES.MODE_CBC, iv) - decrypted_data = cipher.decrypt(encrypted_data) - decoded = unpad(decrypted_data, AES.block_size) - - return decoded - - -def get_ips(data): - ip_addresses = [] - segments = data.split(b"\x00") - - for segment in segments: - with suppress(Exception): - (_, ip_int, port) = struct.unpack("!BIH", segment) - ip_addr = str(ipaddress.ip_address(ip_int)) - ip_addresses.append(f"{ip_addr}:{port}") - - return ip_addresses - - -def decrypt_strings(data, xor_key): - decoded_strings = [] - current_string = bytearray() - key_index = 0 - num = 0 - key_length = len(xor_key) - - for byte in data: - decoded_byte = byte ^ xor_key[key_index] & 0xFF - if decoded_byte != 0: - current_string.append(decoded_byte) - else: - with suppress(Exception): - dec_str = current_string.decode("utf-8") - dec_str = f"{num - len(dec_str)}|{dec_str}" - decoded_strings.append(dec_str) - current_string.clear() - key_index = (key_index + 1) % key_length - num += 1 - - return decoded_strings - - -def extract_config(filebuf): - end_config = {} - if filebuf[:2] == b"MZ": - try: - pe = pefile.PE(data=filebuf, fast_load=False) - matches = yara_rules.match(data=filebuf) - if matches: - decrypt_offset = "" - c2decrypt = "" - confdecrypt = "" - - for match in matches: - if match.rule != "QakBot5": - continue - for item in match.strings: - if "$c2list" == item.identifier: - c2decrypt = item.instances[0].offset - elif "$campaign" == item.identifier: - confdecrypt = item.instances[0].offset - elif "$decrypt_str" == item.identifier: - decrypt_offset = item.instances[0].offset - - if not (decrypt_offset and c2decrypt and confdecrypt): - return - - aes_pwd_disp = pe.get_dword_from_offset(decrypt_offset + 7) - aes_pwd_rva = pe.get_rva_from_offset(decrypt_offset + 11) + aes_pwd_disp - aes_pwd_size = pe.get_dword_from_offset(decrypt_offset + 15) - aes_pwd = pe.get_data(aes_pwd_rva, aes_pwd_size) - key = get_sha256_hash(aes_pwd) - enc_xor_disp = pe.get_dword_from_offset(decrypt_offset + 40) - enc_xor_rva = pe.get_rva_from_offset(decrypt_offset + 44) + enc_xor_disp - enc_xor_size = pe.get_dword_from_offset(decrypt_offset + 28) - enc_xor = pe.get_data(enc_xor_rva, enc_xor_size) - enc_strs_disp = pe.get_dword_from_offset(decrypt_offset + 22) - enc_strs_rva = pe.get_rva_from_offset(decrypt_offset + 26) + enc_strs_disp - enc_strs_size = pe.get_dword_from_offset(decrypt_offset + 45) - enc_strs = pe.get_data(enc_strs_rva, enc_strs_size) - - iv = enc_xor[:16] - encrypted_buffer = enc_xor[16:] - xor_key = decrypt_aes_cbc(encrypted_buffer, key, iv) - decoded = decrypt_strings(enc_strs, xor_key) - - if not decoded: - return - - c2blob_disp = pe.get_dword_from_offset(c2decrypt + 29) - c2blob_rva = pe.get_rva_from_offset(c2decrypt + 33) + c2blob_disp - c2blob_size_disp = pe.get_dword_from_offset(c2decrypt + 3) - c2blob_size_rva = pe.get_rva_from_offset(c2decrypt + 7) + c2blob_size_disp - c2blob_size = pe.get_word_at_rva(c2blob_size_rva) - c2blob = pe.get_data(c2blob_rva, c2blob_size) - c2blob_pwd_index = str(pe.get_dword_from_offset(c2decrypt + 8)) - - confblob_disp = pe.get_dword_from_offset(confdecrypt + 30) - confblob_rva = pe.get_rva_from_offset(confdecrypt + 34) + confblob_disp - confblob_size_disp = pe.get_dword_from_offset(confdecrypt + 3) - confblob_size_rva = pe.get_rva_from_offset(confdecrypt + 7) + confblob_size_disp - confblob_size = pe.get_word_at_rva(confblob_size_rva) - confblob = pe.get_data(confblob_rva, confblob_size) - - ip_list = [] - config = "" - for val in decoded: - index, aes_pwd = val.split("|") - if index == c2blob_pwd_index: - key = get_sha256_hash(aes_pwd.encode("utf-8")) - iv = c2blob[1:17] - encrypted_buffer = c2blob[17:] - decoded = decrypt_aes_cbc(encrypted_buffer, key, iv) - if decoded: - cncs = decoded[32:] - ip_list = get_ips(cncs) - - if ip_list: - end_config.setdefault("C2s", ip_list) - - iv = confblob[1:17] - encrypted_buffer = confblob[17:] - decoded = decrypt_aes_cbc(encrypted_buffer, key, iv) - - if decoded: - conf = decoded[32:] - config = parse_config(conf) - - if config: - end_config.update(config) - - break - - else: - if not hasattr(pe, "DIRECTORY_ENTRY_RESOURCE"): - return end_config - for rsrc in pe.DIRECTORY_ENTRY_RESOURCE.entries: - for entry in rsrc.directory.entries: - if entry.name is None: - continue - # log.info("id: %s", entry.name) - controllers = [] - config = {} - offset = entry.directory.entries[0].data.struct.OffsetToData - size = entry.directory.entries[0].data.struct.Size - res_data = pe.get_memory_mapped_image()[offset : offset + size] - if str(entry.name) == "307": - # we found the parent process and still need to decrypt/(blzpack) decompress the main DLL - dec_bytes = decrypt_data(res_data) - decompressed = decompress(dec_bytes) - end_config["Loader Build"] = parse_build(pe).decode() - pe2 = pefile.PE(data=decompressed) - if not hasattr(pe2, "DIRECTORY_ENTRY_RESOURCE"): - continue - for rsrc in pe2.DIRECTORY_ENTRY_RESOURCE.entries: - for entry in rsrc.directory.entries: - if entry.name is None: - continue - offset = entry.directory.entries[0].data.struct.OffsetToData - size = entry.directory.entries[0].data.struct.Size - res_data = pe2.get_memory_mapped_image()[offset : offset + size] - if str(entry.name) == "308": - dec_bytes = decrypt_data(res_data) - config = parse_config(dec_bytes) - # log.info("qbot_config: %s", config) - end_config["Core DLL Build"] = parse_build(pe2).decode() - elif str(entry.name) == "311": - dec_bytes = decrypt_data(res_data) - controllers = parse_controllers(dec_bytes) - elif str(entry.name) == "308": - dec_bytes = decrypt_data(res_data) - config = parse_config(dec_bytes) - elif str(entry.name) == "311": - dec_bytes = decrypt_data(res_data) - controllers = parse_binary_c2(dec_bytes) - elif str(entry.name) in ("118", "3719"): - dec_bytes = decrypt_data2(res_data) - controllers = parse_binary_c2_2(dec_bytes) - elif str(entry.name) in ("524", "5812"): - dec_bytes = decrypt_data2(res_data) - config = parse_config(dec_bytes) - elif str(entry.name) in ("18270D2E", "BABA", "103", "89210AF9"): - dec_bytes = decrypt_data3(res_data) - config = parse_config(dec_bytes) - elif str(entry.name) in ("26F517AB", "EBBA", "102", "3C91E639"): - dec_bytes = decrypt_data3(res_data) - controllers = parse_binary_c2_2(dec_bytes) - elif str(entry.name) in ("89290AF9", "COMPONENT_07"): - dec_bytes = decrypt_data4(res_data) - config = parse_config(dec_bytes) - elif str(entry.name) in ("3C91E539", "COMPONENT_08"): - dec_bytes = decrypt_data4(res_data) - controllers = parse_binary_c2_2(dec_bytes) - end_config["Loader Build"] = parse_build(pe).decode() - for k, v in config.items(): - # log.info({ k: v }) - end_config.setdefault(k, v) - # log.info("controllers: %s", controllers) - for controller in controllers: - end_config.setdefault("address", []).append(controller) - except Exception as e: - log.warning(e) - elif filebuf[:1] == b"\x01": - controllers = parse_binary_c2(filebuf[: len(filebuf) - 20]) - for controller in controllers: - end_config.setdefault("address", []).append(controller) - elif b"=" in filebuf: - config = parse_config(filebuf[: len(filebuf) - 20]) - for k, v in config.items(): - end_config.setdefault(k, v) - return end_config - - -if __name__ == "__main__": - import sys - from pathlib import Path - - log.setLevel(logging.DEBUG) - data = Path(sys.argv[1]).read_bytes() - print(extract_config(data)) diff --git a/modules/processing/parsers/CAPE/QuasarRAT.py b/modules/processing/parsers/CAPE/QuasarRAT.py deleted file mode 100644 index 1220071ea7d..00000000000 --- a/modules/processing/parsers/CAPE/QuasarRAT.py +++ /dev/null @@ -1,5 +0,0 @@ -from rat_king_parser.rkp import RATConfigParser - - -def extract_config(data: bytes): - return RATConfigParser(data).report.get("config", {}) diff --git a/modules/processing/parsers/CAPE/Quickbind.py b/modules/processing/parsers/CAPE/Quickbind.py deleted file mode 100644 index ec316d6eb53..00000000000 --- a/modules/processing/parsers/CAPE/Quickbind.py +++ /dev/null @@ -1,87 +0,0 @@ -import logging -import re -import struct -from contextlib import suppress - -import pefile -from Cryptodome.Cipher import ARC4 - -log = logging.getLogger(__name__) -log.setLevel(logging.INFO) - - -def is_hex(hex_string): - if len(hex_string) % 2 != 0: - return False - - if not re.fullmatch(r"[0-9a-fA-F]+", hex_string): - return False - - return True - - -def extract_config(filebuf): - cfg = {} - pe = pefile.PE(data=filebuf) - - data_sections = [s for s in pe.sections if s.Name.find(b".data") != -1] - - if not data_sections: - return None - - data = data_sections[0].get_data() - - offset = 0 - entries = [] - while offset < len(data): - if offset + 8 > len(data): - break - size, key = struct.unpack_from("I4s", data, offset) - if b"\x00\x00\x00" in key or size > 256: - offset += 4 - continue - offset += 8 - data_format = f"{size}s" - encrypted_string = struct.unpack_from(data_format, data, offset)[0] - offset += size - padding = (8 - (offset % 8)) % 8 - offset += padding - - with suppress(IndexError, UnicodeDecodeError, ValueError): - decrypted_result = ARC4.new(key).decrypt(encrypted_string).replace(b"\x00", b"").decode("utf-8") - if decrypted_result and len(decrypted_result) > 1: - entries.append(decrypted_result) - - if entries: - c2s = [] - mutexes = [] - - for item in entries: - if item.count(".") == 3 and re.fullmatch(r"\d+", item.replace(".", "")): - c2s.append(item) - - elif "http" in item: - c2s.append(item) - - elif item.count("-") == 4: - mutexes.append(item) - - elif len(item) in [16] and is_hex(item): - cfg["Encryption Key"] = item - - if c2s: - cfg["C2"] = c2s - - if mutexes: - cfg["Mutex"] = list(set(mutexes)) - - return cfg - - -if __name__ == "__main__": - import sys - from pathlib import Path - - log.setLevel(logging.DEBUG) - data = Path(sys.argv[1]).read_bytes() - print(extract_config(data)) diff --git a/modules/processing/parsers/CAPE/RCSession.py b/modules/processing/parsers/CAPE/RCSession.py deleted file mode 100644 index 7b9e56d89b4..00000000000 --- a/modules/processing/parsers/CAPE/RCSession.py +++ /dev/null @@ -1,121 +0,0 @@ -# Copyright (C) 2015 Kevin O'Reilly kevin.oreilly@contextis.co.uk -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU 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 General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -DESCRIPTION = "RCSession configuration parser." -AUTHOR = "kevoreilly" - -import struct - -import pefile -import yara - -rule_source = """ -rule RCSession -{ - meta: - author = "kevoreilly" - description = "RCSession Payload" - cape_type = "RCSession Payload" - strings: - $a1 = {56 33 F6 39 74 24 08 7E 4C 53 57 8B F8 2B FA 8B C6 25 03 00 00 80 79 05 48 83 C8 FC 40 83 E8 00 74 19 48 74 0F 48 74 05 6B C9 09 EB 15 8B C1 C1 E8 02 EB 03 8D 04 09 2B C8} - $a2 = {83 C4 10 85 C0 74 ?? BE ?? ?? ?? ?? 89 74 24 10 E8 ?? ?? ?? ?? 6A 03 68 48 0B 00 00 56 53 57 68 02 00 00 80 E8 ?? ?? ?? ?? 83 C4 18 85 C0 74 18 E8 ?? ?? ?? ?? 6A 03 68 48} - condition: - (any of ($a*)) -} -""" - -MAX_IP_STRING_SIZE = 16 # aaa.bbb.ccc.ddd\0 -UINT_MAX = 0xFFFFFFFF - - -def yara_scan(raw_data, rule_name): - addresses = {} - yara_rules = yara.compile(source=rule_source) - matches = yara_rules.match(data=raw_data) - for match in matches: - if match.rule == "RCSession": - for item in match.strings: - if item.identifier == rule_name: - addresses[item.identifier] = item.instances[0].offset - return addresses - - -def unicode_string_from_offset(buffer, offset, max): - return buffer[offset : offset + max].decode("utf-16") - - -def decode(ciphertext, size, key): - - if size == 0: - return - - v4 = 0 - decoded_chars = bytearray(size) - - while v4 < size: - if v4 % 4 == 0: - key = (key + (key >> 4)) & UINT_MAX - elif v4 % 4 == 1: - v6 = (2 * key) & UINT_MAX - key = (key - v6) & UINT_MAX - elif v4 % 4 == 2: - v6 = (key >> 2) & UINT_MAX - key = (key - v6) & UINT_MAX - else: - key = (key * 9) & UINT_MAX - decoded_chars[v4] = struct.unpack("B", ciphertext[v4 : v4 + 1])[0] ^ (key & 0xFF) - v4 += 1 - - return decoded_chars - - -def extract_config(filebuf): - pe = pefile.PE(data=filebuf, fast_load=False) - image_base = pe.OPTIONAL_HEADER.ImageBase - decrypt_config = yara_scan(filebuf, "$a2") - if decrypt_config: - yara_offset = int(decrypt_config["$a2"]) - else: - return - - config_rva = struct.unpack("i", filebuf[yara_offset + 8 : yara_offset + 12])[0] - image_base - config_offset = pe.get_offset_from_rva(config_rva) - size = struct.unpack("i", filebuf[yara_offset + 88 : yara_offset + 92])[0] - key = struct.unpack("i", filebuf[config_offset + 128 : config_offset + 132])[0] - end_config = {} - tmp_config = decode(filebuf[config_offset : config_offset + size], size, key) - - c2_address = str(tmp_config[156 : 156 + MAX_IP_STRING_SIZE]) - if c2_address: - end_config.setdefault("c2_address", []).append(c2_address) - c2_address = str(tmp_config[224 : 224 + MAX_IP_STRING_SIZE]) - if c2_address: - end_config.setdefault("c2_address", []).append(c2_address) - installdir = unicode_string_from_offset(bytes(tmp_config), 0x2A8, 128) - if installdir: - end_config["directory"] = installdir - executable = unicode_string_from_offset(tmp_config, 0x4B0, 128) - if executable: - end_config["filename"] = executable - servicename = unicode_string_from_offset(tmp_config, 0x530, 128) - if servicename: - end_config["servicename"] = servicename - displayname = unicode_string_from_offset(tmp_config, 0x738, 128) - if displayname: - end_config["servicedisplayname"] = displayname - description = unicode_string_from_offset(tmp_config, 0x940, 512) - if description: - end_config["servicedescription"] = description - - return end_config diff --git a/modules/processing/parsers/CAPE/REvil.py b/modules/processing/parsers/CAPE/REvil.py deleted file mode 100644 index c5c20c48439..00000000000 --- a/modules/processing/parsers/CAPE/REvil.py +++ /dev/null @@ -1,85 +0,0 @@ -# Copyright (C) 2019 R3MRUM (https://twitter.com/R3MRUM) -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU 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 General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -#!/usr/bin/python - -import json -import struct - -import pefile - - -def getSectionNames(sections): - return [section.Name.partition(b"\0")[0] for section in sections] - - -def getREvilKeyAndConfig(pesections, section_name): - for section in pesections: - if section.Name.partition(b"\0")[0] == section_name: - data = section.get_data() - if len(data) > 32: - key = data[:32] - encoded_config = data[32:] - return key, encoded_config - - -def decodeREvilConfig(config_key, config_data): - init255 = list(range(256)) - - key = config_key - config_len = struct.unpack(". - -DESCRIPTION = "RedLeaf configuration parser." -AUTHOR = "kevoreilly" - -import struct - -import pefile -import yara - -rule_source = """ -rule RedLeaf -{ - meta: - author = "kev" - description = "RedLeaf configuration parser." - cape_type = "RedLeaf Payload" - strings: - $crypto = {6A 10 B8 ?? ?? ?? 10 E8 ?? ?? 01 00 8B F1 89 75 E4 8B 7D 08 83 CF 07 81 FF FE FF FF 7F 76 05 8B 7D 08 EB 29 8B 4E 14 89 4D EC D1 6D EC 8B C7 33 D2 6A 03 5B F7 F3 8B 55 EC 3B D0 76 10 BF FE FF FF} - $decrypt_config = {55 8B EC 83 EC 20 A1 98 9F 03 10 33 C5 89 45 FC 56 33 F6 33 C0 80 B0 ?? ?? ?? ?? ?? 40 3D ?? ?? ?? ?? 72 F1 68 70 99 03 10 56 56 FF 15 2C 11 03 10 FF 15 B8 11 03 10 3D B7 00 00 00 75 06 56 E8 5F 9E} - condition: - //check for MZ Signature at offset 0 - uint16(0) == 0x5A4D - - and - - $crypto and $decrypt_config -} -""" - -MAX_STRING_SIZE = 64 -MAX_IP_STRING_SIZE = 16 # aaa.bbb.ccc.ddd\0 - - -def yara_scan(raw_data, rule_name): - addresses = {} - yara_rules = yara.compile(source=rule_source) - matches = yara_rules.match(data=raw_data) - for match in matches: - if match.rule == "RedLeaf": - for item in match.strings: - if item.identifier == rule_name: - addresses[item.identifier] = item.instances[0].offset - return addresses - - -def pe_data(pe, va, size): - image_base = pe.OPTIONAL_HEADER.ImageBase - rva = va - image_base - return pe.get_data(rva, size) - - -def string_from_offset(buffer, offset): - return buffer[offset : offset + MAX_STRING_SIZE].split(b"\0", 1)[0] - - -def unicode_string_from_offset(buffer, offset): - return buffer[offset : offset + MAX_STRING_SIZE].split(b"\x00\x00", 1)[0] - - -def extract_config(filebuf): - pe = pefile.PE(data=filebuf, fast_load=False) - image_base = pe.OPTIONAL_HEADER.ImageBase - - decrypt_config = yara_scan(filebuf, "$decrypt_config") - - if decrypt_config: - yara_offset = int(decrypt_config["$decrypt_config"]) - else: - return - - config_rva = struct.unpack("i", filebuf[yara_offset + 23 : yara_offset + 27])[0] - image_base - config_offset = pe.get_offset_from_rva(config_rva) - xor_key = struct.unpack("b", filebuf[yara_offset + 27 : yara_offset + 28])[0] - config_size = struct.unpack("i", filebuf[yara_offset + 30 : yara_offset + 34])[0] - tmp_config = "".join([chr(xor_key ^ ord(x)) for x in filebuf[config_offset : config_offset + config_size]]) - end_config = {} - c2_address = tmp_config[8 : 8 + MAX_IP_STRING_SIZE] - if c2_address: - end_config.setdefault("c2_address", []).append(c2_address) - c2_address = tmp_config[0x48 : 0x48 + MAX_IP_STRING_SIZE] - if c2_address: - end_config.setdefault("c2_address", []).append(c2_address) - c2_address = tmp_config[0x88 : 0x88 + MAX_IP_STRING_SIZE] - if c2_address: - end_config.setdefault("c2_address", []).append(c2_address) - missionid = string_from_offset(tmp_config, 0x1EC) - if missionid: - end_config["missionid"] = missionid - mutex = unicode_string_from_offset(tmp_config, 0x508) - if mutex: - end_config["mutex"] = mutex - key = string_from_offset(tmp_config, 0x832) - if key: - end_config["key"] = key - - return end_config diff --git a/modules/processing/parsers/CAPE/RedLine.py b/modules/processing/parsers/CAPE/RedLine.py deleted file mode 100644 index 2110cbbdeec..00000000000 --- a/modules/processing/parsers/CAPE/RedLine.py +++ /dev/null @@ -1,182 +0,0 @@ -# Thanks to Gi7w0rm -# https://github.com/kevthehermit/RATDecoders/blob/master/malwareconfig/decoders/RedLine.py - -import base64 -import logging -import re -from contextlib import suppress - -from lib.cuckoo.common.dotnet_utils import dotnet_user_strings -from lib.cuckoo.common.integrations.strings import extract_strings - -try: - import dnfile - - HAVE_DNFILE = True -except ImportError: - HAVE_DNFILE = False - -log = logging.getLogger(__name__) -log.setLevel(logging.INFO) - - -def decrypt(str_to_dec, Key): - dec_xor = "" - first_dec = base64.b64decode(str_to_dec) - len_first_dec = len(first_dec) - for i in range(len_first_dec): - Key = Key + str(Key[i % len(Key)]) - a_list = [chr(ord(chr(a)) ^ ord(b)) for a, b in zip(first_dec, Key)] - dec_xor = "".join(a_list) - third_dec = base64.b64decode(dec_xor) - tocut = str(third_dec) - cut = tocut[2:-1] - return cut - - -def extract_config(data): - config_dict = {} - - pattern = re.compile( - Rb"""(?x) - \x02\x72(...)\x70\x7D...\x04 - \x02\x72(...)\x70\x7D...\x04 - \x02\x72(...)\x70\x7D...\x04 - \x02\x72(...)\x70\x7D...\x04 - """ - ) - - pattern2 = re.compile( - Rb"""(?x) - \x72(...)\x70\x0A - \x72(...)\x70\x0B - \x72(...)\x70\x0C - \x72(...)\x70\x0D - """ - ) - - pattern3 = re.compile( - Rb"""(?x) - \x02\x72(...)\x70\x7D...\x04 - \x02\x72(...)\x70\x7D...\x04 - """ - ) - - pattern4 = re.compile( - Rb"""(?x) - \x02\x28...\x0A - \x02\x72(...)\x70\x7D...\x04 - \x02\x72(...)\x70\x7D...\x04 - """ - ) - - pattern5 = re.compile( - Rb"""(?x) - \x72(...)\x70\x80...\x04 - \x72(...)\x70\x80...\x04 - \x72(...)\x70\x80...\x04 - \x72(...)\x70\x80...\x04 - """ - ) - - # If the config file is stored in plaintext format - pattern6 = re.compile( - Rb"""(?x) - \x72(...)\x70\x80...\x04 - \x72(...)\x70\x80...\x04 - """ - ) - patterns = [pattern, pattern2, pattern3, pattern4, pattern5, pattern6] - key = c2 = botnet = base_location = None - - user_strings = extract_strings(data=data, on_demand=True) - if not user_strings: - user_strings = dotnet_user_strings(data=data) - if not user_strings: - return - - with suppress(Exception): - base_location = user_strings.index("Yandex\\YaAddon") - if base_location: - # newer samples - with suppress(Exception): - key = user_strings[base_location - 1] - c2 = decrypt(user_strings[base_location - 3], key) - if not c2 or "." not in c2: - c2 = decrypt(user_strings[base_location - 4], key) - botnet = decrypt(user_strings[base_location - 3], key) - else: - botnet = decrypt(user_strings[base_location - 2], key) - - # older samples - if not c2 or "." not in c2: - with suppress(Exception): - key = user_strings[base_location + 3] - c2 = decrypt(user_strings[base_location + 1], key) - botnet = decrypt(user_strings[base_location + 2], key) - - base_location = None - with suppress(Exception): - if "Authorization" in user_strings: - base_location = user_strings.index("Authorization") - if base_location: - if not c2 or "." not in c2: - delta = base_location - while True: - delta += 1 - if "==" in user_strings[delta]: - c2 = user_strings[delta] - if "=" in user_strings[delta + 1]: - botnet = user_strings[delta + 1] - key = user_strings[delta + 2] - if "=" in key: - key = user_strings[delta + 3] - else: - botnet = None - key = user_strings[delta + 1] - c2 = decrypt(c2, key) - if botnet: - botnet = decrypt(botnet, key) - break - - if not c2 or "." not in c2 and HAVE_DNFILE: - with suppress(Exception): - dn = dnfile.dnPE(data=data) - for p in patterns: - extracted = [] - for match in p.findall(data): - for item in match: - user_string = dn.net.user_strings.get(int.from_bytes(item, "little")).value - if user_string: - extracted.append(user_string) - if extracted: - # Case-1: If the config file is stored in encrypted format - if len(extracted) == 3: - key = extracted[2] - c2 = decrypt(extracted[0], key) - botnet = decrypt(extracted[1], key) - if "." in c2: - break - - # Case-2: If the config file is stored in plaintext format - else: - c2 = extracted[0] - botnet = extracted[1] - dn.close() - - if not c2 or "." not in c2: - return - - config_dict = {"C2": c2, "Botnet": botnet, "Key": key} - if "Authorization" in user_strings: - base_location = user_strings.index("Authorization") - if base_location: - config_dict["Authorization"] = user_strings[base_location - 1] - return config_dict - - -if __name__ == "__main__": - import sys - - with open(sys.argv[1], "rb") as f: - print(extract_config(f.read())) diff --git a/modules/processing/parsers/CAPE/Remcos.py b/modules/processing/parsers/CAPE/Remcos.py deleted file mode 100644 index a5ebbf9c331..00000000000 --- a/modules/processing/parsers/CAPE/Remcos.py +++ /dev/null @@ -1,207 +0,0 @@ -# This file is part of CAPE Sandbox - https://github.com/ctxis/CAPE -# See the file 'docs/LICENSE' for copying permission. -# -# This decoder is based on: -# Decryptor POC for Remcos RAT version 2.7.1 and earlier -# By Talos July 2018 - https://github.com/Cisco-Talos/remcos-decoder -# Updates based on work presented here https://gist.github.com/sysopfb/11e6fb8c1377f13ebab09ab717026c87 - -DESCRIPTION = "Remcos config extractor." -AUTHOR = "threathive,sysopfb,kevoreilly" - -import base64 -import logging -import re -import string -from collections import OrderedDict - -import pefile -from Cryptodome.Cipher import ARC4 - -# From JPCERT -FLAG = {b"\x00": "Disable", b"\x01": "Enable"} - -# From JPCERT -idx_list = { - 0: "Host:Port:Password", - 1: "Assigned name", - 2: "Connect interval", - 3: "Install flag", - 4: "Setup HKCU\\Run", - 5: "Setup HKLM\\Run", - 6: "Setup HKLM\\Explorer\\Run", - 7: "Setup HKLM\\Winlogon\\Shell", - 8: "Setup HKLM\\Winlogon\\Userinit", - 9: "Install path", - 10: "Copy file", - 11: "Startup value", - 12: "Hide file", - 13: "Unknown13", - 14: "Mutex", - 15: "Keylog flag", - 16: "Keylog path", - 17: "Keylog file", - 18: "Keylog crypt", - 19: "Hide keylog file", - 20: "Screenshot flag", - 21: "Screenshot time", - 22: "Take Screenshot option", - 23: "Take screenshot title", - 24: "Take screenshot time", - 25: "Screenshot path", - 26: "Screenshot file", - 27: "Screenshot crypt", - 28: "Mouse option", - 29: "Unknown29", - 30: "Delete file", - 31: "Unknown31", - 32: "Unknown32", - 33: "Unknown33", - 34: "Unknown34", - 35: "Unknown35", - 36: "Audio record time", - 37: "Audio path", - 38: "Audio folder", - 39: "Unknown39", - 40: "Unknown40", - 41: "Connect delay", - 42: "Unknown42", - 43: "Unknown43", - 44: "Unknown44", - 45: "Unknown45", - 46: "Unknown46", - 47: "Unknown47", - 48: "Copy folder", - 49: "Keylog folder", - 50: "Unknown50", - 51: "Unknown51", - 52: "Unknown52", - 53: "Unknown53", - 54: "Keylog file max size (base64)", - 55: "Unknown55 (base64)", - 56: "TLS client certificate (base64)", - 57: "TLS client private key (base64)", - 58: "TLS server certificate (base64)", - 59: "Unknown59", - 60: "Unknown60", - 61: "Unknown61", - 62: "Unknown62", - 63: "Unknown63", - 64: "Unknown64", - 65: "Unknown65", - 66: "Unknown66", -} - -# From JPCERT -setup_list = { - 0: "Temp", - 2: "Root", - 3: "Windows", - 4: "System32", - 5: "Program Files", - 6: "AppData", - 7: "User Profile", - 8: "Application path", -} - -utf_16_string_list = ["Copy file", "Startup value", "Keylog file", "Take screenshot title", "Copy folder", "Keylog folder"] -logger = logging.getLogger(__name__) - - -def get_rsrc(pe): - ret = [] - if not hasattr(pe, "DIRECTORY_ENTRY_RESOURCE"): - return ret - - for resource_type in pe.DIRECTORY_ENTRY_RESOURCE.entries: - name = str(resource_type.name if resource_type.name is not None else pefile.RESOURCE_TYPE.get(resource_type.struct.Id)) - if hasattr(resource_type, "directory"): - for resource_id in resource_type.directory.entries: - if hasattr(resource_id, "directory"): - for resource_lang in resource_id.directory.entries: - data = pe.get_data(resource_lang.data.struct.OffsetToData, resource_lang.data.struct.Size) - ret.append((name, data, resource_lang.data.struct.Size, resource_type)) - - return ret - - -def get_strings(data, min=4): - result = "" - for c in data: - if chr(c) in string.printable: - result += chr(c) - continue - if len(result) >= min: - yield result - result = "" - if len(result) >= min: - yield result - - -def check_version(filedata): - s = "" - # find strings in binary file - slist = get_strings(filedata) - - # find and extract version string e.g. "2.0.5 Pro", "1.7 Free" or "1.7 Light" - for s in slist: - if bool(re.search(r"^\d+\.\d+(\.\d+)?\s+\w+$", s)): - return s - return "" - - -def extract_config(filebuf): - config = {} - - try: - pe = pefile.PE(data=filebuf) - blob = False - ResourceData = get_rsrc(pe) - for rsrc in ResourceData: - if rsrc[0] in ("RT_RCDATA", "SETTINGS"): - blob = rsrc[1] - break - - if blob: - keylen = blob[0] - key = blob[1 : keylen + 1] - decrypted_data = ARC4.new(key).decrypt(blob[keylen + 1 :]) - p_data = OrderedDict() - p_data["Version"] = check_version(filebuf) - - configs = re.split(rb"\|\x1e\x1e\x1f\|", decrypted_data) - - for i, cont in enumerate(configs): - if cont in (b"\x00", b"\x01"): - p_data[idx_list[i]] = FLAG[cont] - elif i in (9, 16, 25, 37): - # observed config values in bytes instead of ascii - if cont[0] > 8: - p_data[idx_list[i]] = setup_list[int(chr(cont[0]))] - else: - p_data[idx_list[i]] = setup_list[cont[0]] - elif i in (54, 55, 56, 57, 58): - p_data[idx_list[i]] = base64.b64encode(cont) - elif i == 0: - # various separators have been observed - separator = next((x for x in (b"|", b"\x1e", b"\xff\xff\xff\xff") if x in cont)) - host, port, password = cont.split(separator, 1)[0].split(b":") - p_data["Control"] = f"tcp://{host.decode()}:{port.decode()}:{password.decode()}" - else: - p_data[idx_list[i]] = cont - - for k, v in p_data.items(): - if k in utf_16_string_list: - v = v.decode("utf16").strip("\00") if isinstance(v, bytes) else v - config[k] = v - - except Exception as e: - logger.error(f"Caught an exception: {e}") - - return config - - -if __name__ == "__main__": - import sys - - print(extract_config(open(sys.argv[1], "rb").read())) diff --git a/modules/processing/parsers/CAPE/Retefe.py b/modules/processing/parsers/CAPE/Retefe.py deleted file mode 100644 index 0daf08b9340..00000000000 --- a/modules/processing/parsers/CAPE/Retefe.py +++ /dev/null @@ -1,146 +0,0 @@ -# This is adapted for CAPE from Tomasuh's retefe-unpacker script: -# https://github.com/Tomasuh/retefe-unpacker -# http://tomasuh.github.io/2018/12/28/retefe-unpack.html -# Many thanks to Tomasuh - -DESCRIPTION = "Retefe configuration parser." -AUTHOR = "Tomasuh" - -import struct - -import pefile -import yara - -rule_source = """ -rule Retefe -{ - meta: - author = "Tomasuh" - description = "Retefe Payload" - cape_type = "Retefe Payload" - strings: - $retefe_encoded_buffer = {48 8b 44 24 20 8b 40 08 48 8b 4c 24 20 48 8d 15} - $retefe_xor_seed = {24 20 48 8b 44 24 20 C7 40 08} - $retefe_xor_seed_2ndarg = {89 54 24 10 48 89 4c 24 08 48 83 ec 58 ba} - $retefe_shift_and_sub_match = {c1 e0 ?? b9} - condition: - uint16(0) == 0x5A4D and (all of them) -} -""" - - -def yara_scan(raw_data): - addresses = {} - yara_rules = yara.compile(source=rule_source) - matches = yara_rules.match(data=raw_data) - for match in matches: - if match.rule == "Emotet": - for item in match.strings: - addresses[item.identifier] = item.instances[0].offset - return addresses - - -def number_gen_rec(buffer_size, number): - if number == 1: - return buffer_size - return 0xFFFFFFFF & buffer_size * (0xFFFFFFFF & number_gen_rec(buffer_size, number - 1)) - - -def number_gen(buffer_size, number, shifts, subtract_val): - calculated_number = number_gen_rec(buffer_size, number) - - number = calculated_number << shifts # * 8 - number = subtract_val - number - - return number & 0xFFFFFFFF - - -def pwd_calc(buffer_size, number, shifts, subtract_val): - xor_arr = [] - seed = number_gen(buffer_size, number, shifts, subtract_val) - - while seed: - xor_arr.append(seed & 0xFF) - seed >>= 8 - - return xor_arr - - -def extract_config(filebuf): - pe = pefile.PE(data=filebuf, fast_load=False) - - yara_matches = yara_scan(filebuf) - - if not all( - [ - yara_matches.get(key) - for key in ("$retefe_xor_seed", "$retefe_xor_seed_2ndarg", "$retefe_shift_and_sub_match", "$retefe_encoded_buffer") - ] - ): - return - - # Offset to seed for xor - offset = int(yara_matches["$retefe_xor_seed"]) - # Offset to value that will be used to take xor^value - offset2 = int(yara_matches["$retefe_xor_seed_2ndarg"]) - # Offset to values that will be used in part of subtraction and shifts of xor^value - offset3 = int(yara_matches["$retefe_shift_and_sub_match"]) - offset4 = int(yara_matches["$retefe_encoded_buffer"]) - - # Offset starts at match, we want end of match - seed_val = struct.unpack(". -import struct -from itertools import cycle - -import pefile -import yara - -rule_source = """ -rule SquirrelWaffle -{ - strings: - $config = {83 C2 04 83 C1 04 83 EE 04 73 EF 83 FE FC 74 34 8A 02 3A 01 75 27 83 FE FD 74 29 8A 42 01 3A 41 01 75 1A 83 FE FE 74 1C 8A 42 02 3A 41 02 75 0D} - $decode = {F7 75 ?? 83 7D ?? 10 8D 4D ?? 8D 45 ?? C6 45 ?? 00 0F 43 4D ?? 83 7D ?? 10 0F 43 45 ?? 8A 04 10 32 04 39} - $c2key = {83 EC 18 8B CC 89 A5 [4] 6A 05 C7 41 ?? 00 00 00 00 C7 41 ?? 0F 00 00 00 68} - condition: - uint16(0) == 0x5A4D and any of them -} -""" - -yara_rules = yara.compile(source=rule_source) - -MAX_STRING_SIZE = 32 - - -def string_from_offset(data, offset): - return data[offset : offset + MAX_STRING_SIZE].split(b"\0", 1)[0] - - -def extract_rdata(pe): - for section in pe.sections: - if b".rdata" in section.Name: - return section.get_data(section.VirtualAddress, section.SizeOfRawData) - return None - - -def xor_data(data, key): - return bytes(c ^ k for c, k in zip(data, cycle(key))) - - -def extract_config(data): - config = {} - pe = None - try: - pe = pefile.PE(data=data) - except Exception: - return config - - if pe is not None: - rdata = extract_rdata(pe) - if len(rdata) == 0: - return config - chunks = [x for x in rdata.split(b"\x00") if x != b""] - for i, line in enumerate(chunks): - if len(line) > 100: - try: - decrypted = xor_data(line, chunks[i + 1]).decode() - if "\r\n" in decrypted and "|" not in decrypted: - config["IP Blocklist"] = list(filter(None, decrypted.split("\r\n"))) - elif "|" in decrypted and "." in decrypted and "\r\n" not in decrypted: - config["URLs"] = list(filter(None, decrypted.split("|"))) - except Exception: - continue - matches = yara_rules.match(data=data) - if not matches: - return config - for match in matches: - if match.rule != "SquirrelWaffle": - continue - for item in match.strings: - if "$c2key" in item.identifier: - c2key_offset = item.instances[0].offset - key_rva = struct.unpack("i", data[c2key_offset + 28 : c2key_offset + 32])[0] - pe.OPTIONAL_HEADER.ImageBase - key_offset = pe.get_offset_from_rva(key_rva) - config["C2 key"] = string_from_offset(data, key_offset).decode() - return config diff --git a/modules/processing/parsers/CAPE/Stealc.py b/modules/processing/parsers/CAPE/Stealc.py deleted file mode 100644 index b9259f3d9ac..00000000000 --- a/modules/processing/parsers/CAPE/Stealc.py +++ /dev/null @@ -1,106 +0,0 @@ -import struct -from contextlib import suppress - -import pefile -import yara - -# Hash = 619751f5ed0a9716318092998f2e4561f27f7f429fe6103406ecf16e33837470 - -RULE_SOURCE = """rule StealC -{ - meta: - author = "Yung Binary" - hash = "619751f5ed0a9716318092998f2e4561f27f7f429fe6103406ecf16e33837470" - strings: - $decode_1 = { - 6A ?? - 68 ?? ?? ?? ?? - 68 ?? ?? ?? ?? - E8 ?? ?? ?? ?? - 83 C4 0C - A3 ?? ?? ?? ?? - } - - condition: - $decode_1 -}""" - - -def yara_scan(raw_data): - yara_rules = yara.compile(source=RULE_SOURCE) - matches = yara_rules.match(data=raw_data) - - for match in matches: - for block in match.strings: - for instance in block.instances: - yield instance.offset - - -def xor_data(data, key): - decoded = bytearray() - for i in range(len(data)): - decoded.append(data[i] ^ key[i]) - return decoded - - -def extract_config(data): - config_dict = {} - - # Attempt to extract via old method - try: - domain = "" - uri = "" - lines = data.decode().split("\n") - for line in lines: - if line.startswith("http") and "://" in line: - domain = line - if line.startswith("/") and line[-4] == ".": - uri = line - if domain and uri: - config_dict.setdefault("C2", []).append(f"{domain}{uri}") - except Exception: - pass - - # Try with new method - if not config_dict.get("C2"): - with suppress(Exception): - # config_dict["Strings"] = [] - pe = pefile.PE(data=data, fast_load=False) - image_base = pe.OPTIONAL_HEADER.ImageBase - domain = "" - uri = "" - for str_decode_offset in yara_scan(data): - str_size = int(data[str_decode_offset + 1]) - # Ignore size 0 strings - if not str_size: - continue - - key_rva = data[str_decode_offset + 3 : str_decode_offset + 7] - encoded_str_rva = data[str_decode_offset + 8 : str_decode_offset + 12] - # dword_rva = data[str_decode_offset + 21 : str_decode_offset + 25] - - key_offset = pe.get_offset_from_rva(struct.unpack("i", key_rva)[0] - image_base) - encoded_str_offset = pe.get_offset_from_rva(struct.unpack("i", encoded_str_rva)[0] - image_base) - # dword_offset = hex(struct.unpack("i", dword_rva)[0])[2:] - - key = data[key_offset : key_offset + str_size] - encoded_str = data[encoded_str_offset : encoded_str_offset + str_size] - decoded_str = xor_data(encoded_str, key).decode() - if decoded_str.startswith("http") and "://" in decoded_str: - domain = decoded_str - elif decoded_str.startswith("/") and decoded_str[-4] == ".": - uri = decoded_str - # else: - # config_dict["Strings"].append({f"dword_{dword_offset}" : decoded_str}) - - if domain and uri: - config_dict.setdefault("C2", []).append(f"{domain}{uri}") - - return config_dict - - -if __name__ == "__main__": - import sys - - with open(sys.argv[1], "rb") as f: - print(extract_config(f.read())) diff --git a/modules/processing/parsers/CAPE/Strrat.py b/modules/processing/parsers/CAPE/Strrat.py deleted file mode 100644 index c6d5390185c..00000000000 --- a/modules/processing/parsers/CAPE/Strrat.py +++ /dev/null @@ -1,80 +0,0 @@ -# MIT License -# -# Copyright (c) 2021 enzok -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in all -# copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. - -import base64 -import zipfile -from hashlib import pbkdf2_hmac - -from Cryptodome.Cipher import AES - -from lib.cuckoo.common.utils import store_temp_file - - -def unpad(s): - return s[: -s[-1]] - - -def unzip_config(filepath): - data = "" - try: - with zipfile.ZipFile(filepath.decode()) as z: - for name in z.namelist(): - if "config.txt" in name: - data = z.read(name) - break - except Exception: - return - return data - - -def aesdecrypt(data, passkey): - iv = data[4:20] - key = pbkdf2_hmac("sha1", passkey, iv, 65536, 16) - aes = AES.new(key, AES.MODE_CBC, iv) - return unpad(aes.decrypt(data[20:])) - - -def decode(data): - decoded = "" - try: - data = base64.b64decode(data) - except Exception as exc: - return exc - if data: - passkey = b"strigoi" - try: - decoded = aesdecrypt(data, passkey) - except Exception: - return - return decoded.decode() - - -def extract_config(data): - raw_config = {} - configdata = "" - tmpzip = store_temp_file(data, "badjar.zip", b"strrat_tmp") - configdata = unzip_config(tmpzip) - - if configdata: - raw_config["config"] = decode(configdata) - - return raw_config diff --git a/modules/processing/parsers/CAPE/TSCookie.py b/modules/processing/parsers/CAPE/TSCookie.py deleted file mode 100644 index 4575ea30d9d..00000000000 --- a/modules/processing/parsers/CAPE/TSCookie.py +++ /dev/null @@ -1,170 +0,0 @@ -#!/usr/bin/env python -# -# LICENSE -# the GNU General Public License version 2 -# -# Credit to JPCERT - this is derived from https://github.com/JPCERTCC/aa-tools/blob/master/tscookie_decode.py - -import collections -import re -import sys -from struct import unpack, unpack_from - -import pefile - -# Resource pattern -RESOURCE_PATTERNS = [ - re.compile("\x50\x68(....)\x68(.)\x00\x00\x00(.)\xE8", re.DOTALL), - re.compile("(.)\x68(...)\x00\x68(.)\x00\x00\x00\x6A\x00\xE8(....)\x83(..)\xC3", re.DOTALL), - re.compile("\x04(.....)\x68(.)\x00\x00\x00\x6A\x00\xE8", re.DOTALL), - re.compile("\x56\xBE(....)\x56\x68(.)\x00\x00\x00\x6A\x00\xE8", re.DOTALL), - re.compile("\x53\x68(....)\x6A(.)\x56\xFF", re.DOTALL), -] - -# RC4 key pattern -RC4_KEY_PATTERNS = [ - re.compile("\x80\x68\x80\x00\x00\x00\x50\xC7\x40", re.DOTALL), - re.compile("\x80\x68\x80\x00\x00\x00(...)\x50\x52\x53\xC7\x40", re.DOTALL), -] -RC4_KEY_LENGTH = 0x80 - -# Config pattern -CONFIG_PATTERNS = [ - re.compile("\xC3\x90\x68(....)\xE8(....)\x59\x6A\x01\x58\xC3", re.DOTALL), - re.compile("\x6A\x04\x68(....)\x8D(.....)\x56\x50\xE8", re.DOTALL), -] -CONFIG_SIZE = 0x8D4 - - -# RC4 -def rc4(data, key): - x = 0 - box = list(range(256)) - for i in range(256): - x = (x + box[i] + ord(key[i % len(key)])) % 256 - box[i], box[x] = box[x], box[i] - x = 0 - y = 0 - out = [] - for char in data: - x = (x + 1) % 256 - y = (y + box[x]) % 256 - box[x], box[y] = box[y], box[x] - out.append(chr(ord(char) ^ box[(box[x] + box[y]) % 256])) - - return "".join(out) - - -# helper function for formatting string -def __format_string(data): - return data.split("\x00", 1)[0] - - -# Parse config -def parse_config(config): - config_dict = collections.OrderedDict() - for i in range(4): - if config[0x10 + 0x100 * i] != "\x00": - config_dict[f"Server name #{i + 1}"] = __format_string( - unpack_from("<240s", config, 0x10 + 0x100 * i)[0].decode("utf-16") - ) - config_dict[f"Main port #{i + 1}"] = unpack_from("I', config, 0x604)[0]:X}" - config_dict["Sleep time"] = unpack_from(" 200: - resource_id = ord(unpack("c", data[mr.start() + 8])[0]) - if resource_id == 104: - resource_id = ord(unpack("c", data[mr.start() + 21])[0]) - break - except Exception: - return - if not mr: - sys.exit("[!] Resource id not found") - - for idx in pe.DIRECTORY_ENTRY_RESOURCE.entries: - if str(idx.name) in str(resource_name): - for entry in idx.directory.entries: - if entry.id == resource_id: - try: - data_rva = entry.directory.entries[0].data.struct.OffsetToData - size = entry.directory.entries[0].data.struct.Size - rc_data = pe.get_memory_mapped_image()[data_rva : data_rva + size] - except Exception: - return - - return rc_data - - -def extract_config(data): - try: - dll = pefile.PE(data=data) - except Exception: - return None - - for pattern in CONFIG_PATTERNS: - mc = re.search(pattern, data) - if mc: - try: - (config_rva,) = unpack("=I", data[mc.start() + 3 : mc.start() + 7]) - config_addr = dll.get_physical_by_rva(config_rva - dll.NT_HEADERS.OPTIONAL_HEADER.ImageBase) - enc_config_data = data[config_addr : config_addr + CONFIG_SIZE] - except Exception: - return - - for pattern in RESOURCE_PATTERNS: - mr2 = re.search(pattern, data) - - if mr2: - rc2_data = load_resource(dll, data) - key_end = load_rc4key(data) - decode_resource(rc2_data, key_end, "TSCookie.2nd.decode") - - try: - enc_config = enc_config_data[4:] - rc4key = enc_config_data[:4] - config = rc4(enc_config, rc4key) - except Exception: - return - - return parse_config(config) diff --git a/modules/processing/parsers/CAPE/TrickBot.py b/modules/processing/parsers/CAPE/TrickBot.py deleted file mode 100644 index e0824344b62..00000000000 --- a/modules/processing/parsers/CAPE/TrickBot.py +++ /dev/null @@ -1,198 +0,0 @@ -# MIT License -# -# Copyright (c) 2017 Jason Reaves -# Copyright (c) 2019 Graham Austin -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in all -# copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. - -import hashlib -import struct -import xml.etree.ElementTree as ET - -import pefile -import yara -from Cryptodome.Cipher import AES - -rule_source = """ -rule TrickBot -{ - meta: - author = "grahamaustin" - description = "TrickBot Payload" - cape_type = "TrickBot Payload" - strings: - $snippet1 = {B8 ?? ?? 00 00 85 C9 74 32 BE ?? ?? ?? ?? BA ?? ?? ?? ?? BF ?? ?? ?? ?? BB ?? ?? ?? ?? 03 F2 8B 2B 83 C3 04 33 2F 83 C7 04 89 29 83 C1 04 3B DE 0F 43 DA} - condition: - uint16(0) == 0x5A4D and ($snippet1) -} -""" - - -def yara_scan(raw_data, rule_name): - addresses = {} - yara_rules = yara.compile(source=rule_source) - matches = yara_rules.match(data=raw_data) - for match in matches: - if match.rule == "TrickBot": - for item in match.strings: - if item.identifier == rule_name: - addresses[item.identifier] = item.instances[0].offset - return addresses - - -def xor_data(data, key, key_len): - decrypted_blob = b"" - for i, x in enumerate(range(0, len(data), 4)): - xor = struct.unpack("= section.VirtualAddress and rva < section.VirtualAddress + section.Misc_VirtualSize: - return rva - section.VirtualAddress + section.PointerToRawData - - -# Thanks Robert Giczewski - https://malware.love/malware_analysis/reverse_engineering/2020/11/17/trickbots-latest-trick.html -def convert_to_real_ip(ip_str): - octets = ip_str.split(".") - o1 = int(octets[0]) - o2 = int(octets[2]) - o3 = int(octets[3]) - o4 = int(octets[1]) - x = ((~o1 & 0xFF) & 0xB8 | (o1 & 0x47)) ^ ((~o2 & 0xFF) & 0xB8 | (o2 & 0x47)) - o = (o3 & (~o2 & 0xFF)) | ((~o3 & 0xFF) & o2) - result_octets = [ - str(x), - str(((~o & 0xFF) & o4) | (o & (~o4 & 0xFF))), - str(o), - str(((~o2 & 0xFF) & o4) | ((~o4 & 0xFF) & o2)), - ] - return f"{'.'.join(result_octets)}:443" - - -def get_ip(ip_str, tag): - if tag == "srva": - return convert_to_real_ip(ip_str.split(":", 1)[0]) - return ip_str - - -def decode_onboard_config(data): - try: - pe = pefile.PE(data=data) - rsrcs = get_rsrc(pe) - except Exception: - return - if rsrcs != []: - a = rsrcs[0][1] - data = trick_decrypt(a[4:]) - length = struct.unpack_from(". - -import binascii -import struct - -from Cryptodome.PublicKey import RSA - -MAX_STRING_SIZE = 256 - -# JOINER_SECTIONS = { -# 0xE1285E64: "CRC_PUBLIC_KEY", -# 0x8FB1DDE1: "CRC_CLIENT_INI", -# 0xD722AFCB: "CRC_CLIENT_INI", -# 0x4F75CEA7: "CRC_LOADER_DLL", -# 0x90F8AAB5: "CRC_LOADER_DLL", -# 0x7A042A8A: "CRC_INSTALL_INI", -# 0x90F8AAB4: "CRC_CLIENT64", -# 0xDA57D71A: "CRC_WORDLIST", -# 0xC535D8BF: "CRC_LOADER_DLL", -# } - -# INI_PARAMS = { -# 0x4FA8693E: "CRC_SERVERKEY", -# 0xD0665BF6: "CRC_HOSTS", -# 0x656B798A: "CRC_GROUP", -# 0x556AED8F: "CRC_SERVER", -# 0x11271C7F: "CONF_TIMEOUT", -# 0x48295783: "CONFIG_FAIL_TIMEOUT", -# 0xEA9EA760: "CRC_BOOTSTRAP", -# 0x31277BD5: "CRC_TASKTIMEOUT", -# 0x955879A6: "CRC_SENDTIMEOUT", -# 0x9FD13931: "CRC_BCSERVER", -# 0x6DE85128: "CRC_BCTIMEOUT", -# 0xACC79A02: "CRC_KNOCKERTIMEOUT", -# 0x602C2C26: "CRC_KEYLOGLIST", -# 0xD7A003C9: "CRC_CONFIGTIMEOUT", -# 0x18A632BB: "CRC_CONFIGFAILTIMEOUT", -# 0x73177345: "CRC_DGA_SEED_URL", -# 0x510F22D2: "CRC_TORSERVER", -# 0xEC99DF2E: "CRC_EXTERNALIP", -# 0xC61EFA7A: "CRC_DGATLDS", -# 0xDF351E24: "CRC_32BITDOWNLOAD", -# 0x4B214F54: "CRC_64BITDOWNLOAD", -# 0xCD850E68: "DGA_CRC", -# 0xDF2E7488: "DGA_COUNT", -# 0x584E5925: "TIMER", -# } - -SECTION_KEYS = { - 0xD0665BF6: "Domains", - 0x73177345: "DGA Base URL", - 0xCD850E68: "DGA CRC", - 0xC61EFA7A: "DGA TLDs", - 0x510F22D2: "TOR Domains", - 0xDF351E24: "32-bit DLL URLs", - 0x4B214F54: "64-bit DLL URLs", - 0xEC99DF2E: "IP Service", - 0x11271C7F: "Timer", - 0xDF2E7488: "DGA count", - 0x556AED8F: "Server", - 0x4FA8693E: "Encryption key", - 0xD7A003C9: "Config Fail Timeout", - 0x18A632BB: "Config Timeout", - 0x31277BD5: "Task Timeout", - 0x955879A6: "Send Timeout", - 0xACC79A02: "Knocker Timeout", - 0x6DE85128: "BC Timeout", - 0x656B798A: "Botnet ID", - 0xEFC574AE: "Value 11", - # 0x584E5925: 'EndPointer', - 0xD3AA96D0: "New unknown", -} - - -def string_from_offset(buffer, offset): - return buffer[offset : offset + MAX_STRING_SIZE].split(b"\0", 1)[0].decode() - - -def get_config_item(config, offset): - config_string = string_from_offset(config, offset) - return config_string.split(" ") if " " in config_string else config_string - - -def convert_pubkey(pub): - # bit = struct.unpack_from('. - -import struct -from contextlib import suppress - -import pefile - -DESCRIPTION = "WarzoneRAT configuration extractor." -AUTHOR = "enzo" - - -def ksa(key: bytearray) -> bytearray: - sbox = bytearray(256) - for i in range(256): - sbox[i] = i - - j = 0 - for i in range(256): - j = (j + key[i % 250] + sbox[i]) & 0xFF - sbox[i] ^= sbox[j] & 0xFF - sbox[j] ^= sbox[i] & 0xFF - sbox[i] ^= sbox[j] & 0xFF - return sbox - - -def decrypt(sbox: bytearray, src_buf: bytearray) -> bytes: - i, j, k = 0, 0, 0 - dst_buf = bytearray(len(src_buf)) - - while k < len(src_buf): - i += 1 - uc = sbox[i % 256] & 0xFF - c = uc - 256 if uc > 127 else uc - j = j + c - 256 if j + c > 256 else j + c - d = sbox[j % 256] - sbox[i % 256] = d - sbox[j % 256] = uc - e1 = (i >> 3) ^ (32 * j) - e = sbox[e1 % 256] - g1 = ((int.from_bytes(struct.pack(">i", j), "big") >> 3) ^ (32 * i)) & 0xFF - g2 = sbox[g1 % 256] - g = (e + g2) & 0xFF - e = sbox[(j + d) % 256] - h = sbox[(g ^ 0xAA) % 256] - xor_key = (e ^ (h + sbox[(d + uc) % 256])) & 0xFF - dst_buf[k] = src_buf[k] ^ xor_key - i += 1 - k += 1 - - return bytes(dst_buf) - - -def extract_bss_data(pe): - for section in pe.sections: - if b".bss" in section.Name: - return section.get_data(section.VirtualAddress, section.SizeOfRawData) - return None - - -def extract_config(data): - cfg = {} - pe = None - with suppress(Exception): - pe = pefile.PE(data=data, fast_load=False) - if not pe: - return - try: - key = bytearray(250) - bss_data = extract_bss_data(pe) - if not bss_data: - return cfg - key_size = struct.unpack("i", bss_data[:4])[0] - key_bytes = bss_data[4 : 4 + key_size] - for k in range(len(key_bytes)): - key[k] = key_bytes[k] - etxt = bss_data[4 + key_size : 260 + key_size] - dtxt = decrypt(ksa(key), bytearray(etxt)) - - offset = 4 - c2_size = struct.unpack("i", dtxt[:offset])[0] - c2_host = dtxt[offset : offset + c2_size].decode("utf-16") - offset += c2_size - c2_port = struct.unpack("H", dtxt[offset : offset + 2])[0] - cfg["C2"] = f"{c2_host}:{c2_port}" - offset += 2 - # unk1 = dtxt[offset : offset + 7] - offset += 7 - unk2_size = struct.unpack("i", dtxt[offset : offset + 4])[0] - offset += 4 - # unk2 = dtxt[offset : offset + unk2_size] - offset += unk2_size - # unk3 = dtxt[offset : offset + 2] - offset += 2 - runkey_size = struct.unpack("i", dtxt[offset : offset + 4])[0] - offset += 4 - cfg["Run Key Name"] = dtxt[offset : offset + runkey_size].decode("utf-16") - except struct.error: - # there is a lot of failed data validation muting it - return - except Exception as e: - print("warzone", e) - - return cfg - - -if __name__ == "__main__": - import sys - from pathlib import Path - - data = Path(sys.argv[1]).read_bytes() - print(extract_config(data)) diff --git a/modules/processing/parsers/CAPE/XWorm.py b/modules/processing/parsers/CAPE/XWorm.py deleted file mode 100644 index 1220071ea7d..00000000000 --- a/modules/processing/parsers/CAPE/XWorm.py +++ /dev/null @@ -1,5 +0,0 @@ -from rat_king_parser.rkp import RATConfigParser - - -def extract_config(data: bytes): - return RATConfigParser(data).report.get("config", {}) diff --git a/modules/processing/parsers/CAPE/XenoRAT.py b/modules/processing/parsers/CAPE/XenoRAT.py deleted file mode 100644 index 1220071ea7d..00000000000 --- a/modules/processing/parsers/CAPE/XenoRAT.py +++ /dev/null @@ -1,5 +0,0 @@ -from rat_king_parser.rkp import RATConfigParser - - -def extract_config(data: bytes): - return RATConfigParser(data).report.get("config", {}) diff --git a/modules/processing/parsers/CAPE/Zloader.py b/modules/processing/parsers/CAPE/Zloader.py deleted file mode 100644 index eb0027cb191..00000000000 --- a/modules/processing/parsers/CAPE/Zloader.py +++ /dev/null @@ -1,139 +0,0 @@ -# Copyright (C) 2020 Kevin O'Reilly (kevoreilly@gmail.com) -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU 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 General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -DESCRIPTION = "Zloader configuration parser" -AUTHOR = "kevoreilly" - -import logging -import struct - -import pefile -import yara -from Cryptodome.Cipher import ARC4 - -log = logging.getLogger(__name__) - -rule_source = """ -rule Zloader -{ - meta: - author = "kevoreilly, enzok" - description = "Zloader Payload" - cape_type = "Zloader Payload" - strings: - $rc4_init = {31 [1-3] 66 C7 8? 00 01 00 00 00 00 90 90 [0-5] 8? [5-90] 00 01 00 00 [0-15] (74|75)} - $decrypt_conf = {e8 ?? ?? ?? ?? e8 ?? ?? ?? ?? e8 ?? ?? ?? ?? e8 ?? ?? ?? ?? 68 ?? ?? ?? ?? 68 ?? ?? ?? ?? e8 ?? ?? ?? ?? 83 c4 08 e8 ?? ?? ?? ??} - $decrypt_conf_1 = {48 8d [5] [0-6] e8 [4] 48 [3-4] 48 [3-4] 48 [6] E8} - $decrypt_conf_2 = {48 8d [5] 4? [5] e8 [4] 48 [3-4] 48 8d [5] E8 [4] 48} - $decrypt_key_1 = {66 89 C2 4? 8D 0D [3] 00 4? B? FC 03 00 00 E8 [4] 4? 83 C4} - $decrypt_key_2 = {48 8d 0d [3] 00 66 89 ?? 4? 89 F0 4? [2-5] E8 [4-5] 4? 83 C4} - $decrypt_key_3 = {48 8d 0d [3] 00 e8 [4] 66 89 [3] b? [4] e8 [4] 66 8b} - condition: - uint16(0) == 0x5A4D and 1 of ($decrypt_conf*) and (1 of ($decrypt_key*) or $rc4_init) -} -""" -MAX_STRING_SIZE = 32 - -yara_rules = yara.compile(source=rule_source) - - -def decrypt_rc4(key, data): - cipher = ARC4.new(key) - return cipher.decrypt(data) - - -def string_from_offset(data, offset): - return data[offset : offset + MAX_STRING_SIZE].split(b"\0", 1)[0] - - -def extract_config(filebuf): - end_config = {} - pe = pefile.PE(data=filebuf, fast_load=False) - image_base = pe.OPTIONAL_HEADER.ImageBase - matches = yara_rules.match(data=filebuf) - if not matches: - return - conf_type = "" - decrypt_key = "" - conf_size = 1020 - for match in matches: - if match.rule != "Zloader": - continue - for item in match.strings: - if "$decrypt_conf" == item.identifier: - decrypt_conf = item.instances[0].offset + 21 - conf_type = "1" - elif "$decrypt_conf_1" == item.identifier: - decrypt_conf = item.instances[0].offset - cva = 3 - conf_type = "2" - elif "$decrypt_conf_2" == item.identifier: - decrypt_conf = item.instances[0].offset - cva = 3 - conf_type = "2" - elif "$decrypt_key_1" == item.identifier: - decrypt_key = item.instances[0].offset - kva_s = 6 - elif "$decrypt_key_2" == item.identifier: - decrypt_key = item.instances[0].offset - kva_s = 3 - elif "$decrypt_key_3" == item.identifier: - decrypt_key = item.instances[0].offset - kva_s = 3 - - if conf_type == "1": - va = struct.unpack("I", filebuf[decrypt_conf : decrypt_conf + 4])[0] - key = string_from_offset(filebuf, pe.get_offset_from_rva(va - image_base)) - data_offset = pe.get_offset_from_rva(struct.unpack("I", filebuf[decrypt_conf + 5 : decrypt_conf + 9])[0] - image_base) - enc_data = filebuf[data_offset:].split(b"\0\0", 1)[0] - raw = decrypt_rc4(key, enc_data) - items = list(filter(None, raw.split(b"\x00\x00"))) - end_config["Botnet name"] = items[1].lstrip(b"\x00") - end_config["Campaign ID"] = items[2] - for item in items: - item = item.lstrip(b"\x00") - if item.startswith(b"http"): - end_config.setdefault("address", []).append(item) - elif len(item) == 16: - end_config["RC4 key"] = item - elif conf_type == "2" and decrypt_key: - conf_va = struct.unpack("I", filebuf[decrypt_conf + cva : decrypt_conf + cva + 4])[0] - conf_offset = pe.get_offset_from_rva(conf_va + pe.get_rva_from_offset(decrypt_conf) + cva + 4) - # if not conf_size: - # conf_size = struct.unpack("I", filebuf[decrypt_key + size_s : decrypt_key + size_s + 4])[0] - key_va = struct.unpack("I", filebuf[decrypt_key + kva_s : decrypt_key + kva_s + 4])[0] - key_offset = pe.get_offset_from_rva(key_va + pe.get_rva_from_offset(decrypt_key) + kva_s + 4) - key = string_from_offset(filebuf, key_offset) - conf_data = filebuf[conf_offset : conf_offset + conf_size] - raw = decrypt_rc4(key, conf_data) - items = list(filter(None, raw.split(b"\x00\x00"))) - end_config["Botnet name"] = items[0].decode("utf-8") - end_config["Campaign ID"] = items[1].decode("utf-8") - for item in items: - item = item.lstrip(b"\x00") - if item.startswith(b"http"): - end_config.setdefault("address", []).append(item.decode("utf-8")) - elif b"PUBLIC KEY" in item: - end_config["Public key"] = item.decode("utf-8").replace("\n", "") - - return end_config - - -if __name__ == "__main__": - import sys - from pathlib import Path - - log.setLevel(logging.DEBUG) - data = Path(sys.argv[1]).read_bytes() - print(extract_config(data)) diff --git a/modules/processing/parsers/CAPE/__init__.py b/modules/processing/parsers/CAPE/__init__.py deleted file mode 100644 index f39e5e8d683..00000000000 --- a/modules/processing/parsers/CAPE/__init__.py +++ /dev/null @@ -1 +0,0 @@ -# Init diff --git a/modules/processing/parsers/CAPE/deprecated/JavaDropper.py b/modules/processing/parsers/CAPE/deprecated/JavaDropper.py deleted file mode 100644 index af210be7b1f..00000000000 --- a/modules/processing/parsers/CAPE/deprecated/JavaDropper.py +++ /dev/null @@ -1,105 +0,0 @@ -#!/usr/bin/env python -import hashlib -import string -import zlib -from base64 import b64decode -from io import StringIO -from zipfile import ZipFile - -# Non Standard Imports -from Cryptodome.Cipher import AES, ARC4, XOR - -# Helper Functions Go Here - - -def string_print(line): - return [x for x in line if x in string.printable] - - -#### Ciphers #### -def decrypt_RC4(enckey, data): - cipher = ARC4.new(enckey) - return cipher.decrypt(data) - - -def decrypt_AES(enckey, data): - cipher = AES.new(enckey) - return cipher.decrypt(data) - - -def decrypt_XOR(enckey, data): - cipher = XOR.new(enckey) - return cipher.decrypt(data) - - -def parse_ek(key, drop): - enc_key = key[:16] - coded = drop - drop_details = key[16:] - decoded = decrypt_AES(enc_key, coded) - for section in drop_details.split(","): - print(b64decode(section).decode("hex")) - return decoded - - -def parse_load(key, drop): - raw_key = f"{key}ALSKEOPQLFKJDUSIKSJAUIE" - enc_key = hashlib.sha256(raw_key).hexdigest() - return decrypt_RC4(enc_key, drop) - - -def parse_stub(drop): - keys = ("0kwi38djuie8oq89", "0B4wCrd5N2OxG93h") - - for key in keys: - decoded = decrypt_AES(key, drop) - if "META-INF" in decoded: - print("Found Embedded Jar") - return decoded - if "Program" in decoded: - print("Found Embedded EXE") - return decoded - - -def parse_xor(key, drop): - key2 = 'FYj&w3bd"m/kSZjD' - decoded = decrypt_XOR(key2, drop) - return zlib.decompress(decoded, 16 + zlib.MAX_WBITS) - - -# Jar Parser -def extract_config(raw_data): - decoded = False - jar_data = StringIO(raw_data) - with ZipFile(jar_data, "r") as jar: - files = jar.namelist() - if "e" in files and "k" in files: - print("Found EK Dropper") - key = jar.read("k") - drop = jar.read("e") - decoded = parse_ek(key, drop) - - if "config.ini" in files and "password.ini" in files: - print("Found LoadStub Dropper") - key = jar.read("password.ini") - drop = jar.read("config.ini") - decoded = parse_load(key, drop) - - if "stub/stub.dll" in files: - print("Found Stub Dropper") - drop = jar.read("stub/stub.dll") - decoded = parse_stub(drop) - - if "c.dat" in files: - print("Found XOR Dropper") - key_file = b64decode(jar.read("c.dat")) - key_text = decrypt_XOR("\xdd", key_file) - drop_file = key_text.split("\n", 2)[1] - key = key_text.split("\n", 6)[5] - print(key) - decoded = parse_xor(key, jar.read(drop_file)) - - if decoded: - return decoded - else: - print("Unable to decode") diff --git a/modules/processing/parsers/CAPE/deprecated/Nymaim.py b/modules/processing/parsers/CAPE/deprecated/Nymaim.py deleted file mode 100644 index 9be09243a0b..00000000000 --- a/modules/processing/parsers/CAPE/deprecated/Nymaim.py +++ /dev/null @@ -1,264 +0,0 @@ -import re -import string -import struct -from io import StringIO - - -class Stream(StringIO): - def string(self): - r = [] - c = "" - while c != "\x00": - c = self.read(1) - r.append(c) - return "".join(r).strip("\x00") - - def dword(self): - return struct.unpack("I", self.read(4))[0] - - def word(self): - return struct.unpack("H", self.read(2))[0] - - def byte(self): - return struct.unpack("=B", self.read(1))[0] - - -def get_strings(d): - return re.findall("[ -~]{3,}", d) - - -indent_level = 0 -indent_text = " " -silent = False - - -def pprint(*text): - global indent_level, silent - if not silent: - text = " ".join(str(s) for s in text) - print(indent_level * indent_text + text) - - -def rol(x, n, b=32): - n = (b - 1) & n - return x << n | 2**n - 1 & x >> b - n - - -def chunks(data, n): - return [data[i * n : (i + 1) * n] for i in range(len(data) / n)] - - -def ror(n, bits, b=32): - return ((n & b) >> bits) | ((n << (b - bits)) & b) - - -def uint32(i): - return struct.unpack("= self.base else a - return self._data[a : (a + n) if n else None] - - -class NymaimExtractor: - - CFG_DNS = 0x1B69E661 - CFG_TTL = 0xE6F7E88D - CFG_URL = 0x6B02C248 - CFG_DGA_HASH = 0x2AA0AED9 - CFG_ENC_KEY = 0x22E60B51 - CFG_DOMAINS = 0x1D4B5D09 - CFG_RSA_KEY = 0x2F127FFB - CTG_32BIT_TMPL_1 = 0x4C1AD0BB - CTG_32BIT_TMPL_2 = 0x1AE78782 - CTG_64BIT_TMPL = 0xF34A67FF - CFT_NOTEPAD_TMPL = 0xB2EA894D - CFG_FAKE_ERROR_MSG = 0xFCCE74B6 - CFG_PEER_DOMAINS = 0xF212B5AF - - CFG_BINARY_TYPES = { - 1: "botnet_peer", - 20: "dropper", - 30: "payload", - } - - def __init__(self): - pass - - def nymaim_decrypt_data_2(self, raw, key0, key1): - """ - decrypt final config (only raw data, keys passed as parameters) - """ - prev_chr = 0 - result = "" - for c in raw: - bl = ((key0 & 0x000000FF) + prev_chr) & 0xFF - key0 = (key0 & 0xFFFFFF00) + bl - prev_chr = ord(c) ^ bl - result += chr(prev_chr) - key0 = (key0 + key1) & 0xFFFFFFFF - key0 = ((key0 & 0x00FFFFFF) << 8) + ((key0 & 0xFF000000) >> 24) - return result - - def nymaim_extract_blob(self, mem, ndx): - """ - decrypt final config (read keys and length and decrypt raw data) - """ - key0 = mem.dword(ndx) - key1 = mem.dword(ndx + 4) - len = mem.dword(ndx + 8) - return self.nymaim_decrypt_data_2(mem.read(ndx + 12, len), key0, key1) - - def nymaim_parse_blob(self, blob): - """ - decrypt and interpret config (uses hardcoded hashes) - """ - parsed = {"domains": [], "urls": [], "dns": []} - for hash, raw in NymCfgStream(blob): - try: - pprint(f"<{hash:08x}>: {raw.encode().hex() if len(raw) == 4 else raw}") - if hash == self.CFG_URL: # '48c2026b': - parsed["urls"] += [{"url": append_http(raw[20:].rstrip(";"))}] - elif hash == self.CFG_DGA_HASH: # 'd9aea02a': - parsed["dga_hash"] = [uint32(h) for h in chunks(raw, 4)] - elif hash == self.CFG_DOMAINS: # '095d4b1d': - parsed["domains"] += [{"cnc": append_http(raw[4:].rstrip(";"))}] - elif hash == self.CFG_ENC_KEY: # '510be622': - parsed["encryption_key"] = raw - elif hash == self.CFG_RSA_KEY: # 'fb7f122f': - bits = uint32(raw[:4]) - bytes = bits / 8 - d = raw[4 : 4 + bytes].encode().hex() - e = raw[4 + bytes : 4 + bytes + bytes].encode().hex() - parsed["public_key"] = { - "n": str(int(d, 16)), - "e": int(e, 16), - } - elif hash == self.CFG_TTL: # '8de8f7e6': - if len(raw) == 12: - year, month, day = uint32(raw[-4:]), uint32(raw[4:-4]), uint32(raw[:4]) - parsed["time_restriction"] = f"{year}-{month:02}-{day:02}" - else: - parsed["time_restriction"] = [raw.encode().hex()] - elif hash == self.CFG_DNS: - parsed["dns"] += raw.split(";") - elif hash == self.CTG_32BIT_TMPL_1: - parsed["template_32bit_1"] = raw - elif hash == self.CTG_32BIT_TMPL_2: - parsed["template_32bit_2"] = raw - elif hash == self.CTG_64BIT_TMPL: - parsed["template_64bit_2"] = raw - elif hash == self.CFT_NOTEPAD_TMPL: # notepad template - parsed["notepad_template"] = raw - elif hash == self.CFG_FAKE_ERROR_MSG: # fake error message, shown to user on startup - parsed["fake_error_message"] = raw - elif hash == self.CFG_PEER_DOMAINS: - parsed["domains"] += [{"cnc": x} for x in raw.split(";") if x] - elif (all(c in string.printable for c in raw) and len(raw) > 3) or len( - [c for c in raw if c in string.printable] - ) > 10: - if "other_strings" not in parsed: - parsed["other_strings"] = {} - parsed["other_strings"][hex(hash)] = raw.encode().hex() - except RuntimeError: - # error during parsing... - if "errored_on" not in parsed: - parsed["errored_on"] = [] - parsed["errored_on"] += [{"hash": hash, "raw": raw.encode().hex()}] - return parsed - - def nymaim_brute_blob(self, mem): - """ - bruteforce start index of config in decrypted data (decrypted data contains more than config block). - Lame, but should be stable and fast enough. - """ - for i in reversed(list(range(mem.base, mem.base + mem.dsize - 12))): - blob_len = mem.dword(i + 8) - if 100 < blob_len < 8000: - blob = self.nymaim_extract_blob(mem, i) - if "8.8.8.8" in blob or "rundll" in blob or ("~[" in blob and "]/" in blob and ":53" in blob): - return self.nymaim_parse_blob(blob) - - -def set_prog_version(m, hit, *args): - mem = m.read(hit, 100) - type_id_offset = mem.find("C745D0".decode("hex")) - binary_id_offset = mem.find("C745D4".decode("hex")) - - type_id = uint32(mem[type_id_offset + 3 : type_id_offset + 7]) - binary_id = uint32(mem[binary_id_offset + 3 : binary_id_offset + 7]) - - if type_id in NymaimExtractor.CFG_BINARY_TYPES: - type_name = NymaimExtractor.CFG_BINARY_TYPES[type_id] - else: - type_name = str(type_id) - - return { - "exe_type": type_name, - "exe_version": binary_id, - } - - -def extract_config(raw): - m = Mem(raw, 0) - ext = NymaimExtractor() - return ext.nymaim_brute_blob(m) diff --git a/modules/processing/parsers/CAPE/deprecated/PredatorPain.py b/modules/processing/parsers/CAPE/deprecated/PredatorPain.py deleted file mode 100644 index c4a1652b73b..00000000000 --- a/modules/processing/parsers/CAPE/deprecated/PredatorPain.py +++ /dev/null @@ -1,178 +0,0 @@ -from base64 import b64decode -from binascii import unhexlify - -# import pefile -import pype32 -from Cryptodome.Cipher import AES -from pbkdf2 import PBKDF2 - - -def extract_config(raw_data): - try: - pe = pype32.PE(data=raw_data) - # pe = pefile.PE(data=raw_data) - string_list = get_strings(pe, 2) - vers = get_version(string_list) - if vers == "v12": - config_dict = config_12(string_list) - elif vers == "v13": - key, salt = "PredatorLogger", unhexlify("3000390039007500370038003700390037003800370038003600") - config_dict = config_13(key, salt, string_list) - elif vers == "v14": - key, salt = "EncryptedCredentials", unhexlify("3000390039007500370038003700390037003800370038003600") - config_dict = config_14(key, salt, string_list) - else: - return False - # C2 Line is not a straight domain on this one. - - return config_dict or False - except Exception as e: - print("PREDATORPAIN EXTRACTOR", e) - return False - - -# Helper Functions Go Here - - -def string_clean(line): - return "".join((char for char in line if 32 < ord(char) < 127)) - - -# Cryptodome.Stuffs -def decrypt_string(key, salt, coded): - # try: - # Derive key - generator = PBKDF2(key, salt) - aes_iv = generator.read(16) - aes_key = generator.read(32) - # Crypto - mode = AES.MODE_CBC - cipher = AES.new(aes_key, mode, IV=aes_iv) - return cipher.decrypt(b64decode(coded)).replace("\x00", "") - - -# except Exception: -# return False - - -# Get a list of strings from a section -def get_strings(pe, dir_type): - string_list = [] - m = pe.ntHeaders.optionalHeader.DATA_DIRECTORY[14].info - # m = pe.NT_HEADERS.OPTIONAL_HEADER.DATA_DIRECTORY[14].dump_dict().get("VirtualAddress", {}) - for s in m.netMetaDataStreams[dir_type].info: - string_list.extend(s.values()) - return string_list - - -# Find Version -def get_version(string_list): - # Pred v12 - if "Predator Pain v12 - Server Ran - [" in string_list: - print(" [-] Found Predator Pain v12") - return "v12" - # Pred v13 - elif "Predator Pain v13 - Server Ran - [" in string_list: - print(" [-] Found Predator Pain v13") - return "v13" - # Pred v14 - elif "EncryptedCredentials" in string_list: - print(" [-] Found Predator Pain v14") - return "v14" - - -def config_12(string_list): - config_dict = { - "Version": "Predator Pain v12", - "Email Address": string_list[4], - "Email Password": string_list[5], - "SMTP Server": string_list[6], - "SMTP Port": string_list[7], - "Interval Timer": string_list[8], - "BindFile1": "False" if string_list[9].startswith("ReplaceBind") else "True", - } - - config_dict["BindFile2"] = "False" if string_list[10].startswith("ReplaceBind") else "True" - return config_dict - - -# Turn the strings in to a python config_dict -def config_13(key, salt, string_list): - """ - Identical Strings are not stored multiple times. - We need to check for duplicate passwords which mess up the positionl arguemnts. - """ - - if "email" in string_list[13]: - dup = True - elif "email" in string_list[14]: - dup = False - - config_dict = { - "Version": "Predator Pain v13", - "Email Address": decrypt_string(key, salt, string_list[4]), - "Email Password": decrypt_string(key, salt, string_list[5]), - "SMTP Server": decrypt_string(key, salt, string_list[6]), - "SMTP Port": string_list[7], - "Interval Timer": string_list[8], - "FTP Host": decrypt_string(key, salt, string_list[10]), - "FTP User": decrypt_string(key, salt, string_list[11]), - } - if dup: - config_dict["FTP Pass"] = decrypt_string(key, salt, string_list[5]) - config_dict["PHP Link"] = decrypt_string(key, salt, string_list[12]) - config_dict["Use Email"] = string_list[13] - config_dict["Use FTP"] = string_list[14] - config_dict["Use PHP"] = string_list[15] - config_dict["Download & Exec"] = string_list[20] - config_dict["Bound Files"] = "False" if string_list[19] == "bindfiles" else "True" - else: - config_dict["FTP Pass"] = decrypt_string(key, salt, string_list[12]) - config_dict["PHP Link"] = decrypt_string(key, salt, string_list[13]) - config_dict["Use Email"] = string_list[14] - config_dict["Use FTP"] = string_list[15] - config_dict["Use PHP"] = string_list[16] - config_dict["Download & Exec"] = string_list[21] - config_dict["Bound Files"] = "False" if string_list[20] == "bindfiles" else True - return config_dict - - -# Turn the strings in to a python config_dict -def config_14(key, salt, string_list): - """ - Identical Strings are not stored multiple times. - possible pass and date dupes make it harder to test - """ - - # date Duplicate - if "email" in string_list[18]: - dup = True - elif "email" in string_list[19]: - dup = False - - config_dict = { - "Version": "Predator Pain v14", - "Email Address": decrypt_string(key, salt, string_list[4]), - "Email Password": decrypt_string(key, salt, string_list[5]), - "SMTP Server": decrypt_string(key, salt, string_list[6]), - "SMTP Port": string_list[7], - "Interval Timer": string_list[8], - "FTP Host": decrypt_string(key, salt, string_list[12]), - "FTP User": decrypt_string(key, salt, string_list[13]), - "FTP Pass": decrypt_string(key, salt, string_list[14]), - "PHP Link": decrypt_string(key, salt, string_list[15]), - } - if dup: - config_dict["PHP Link"] = decrypt_string(key, salt, string_list[15]) - config_dict["Use Email"] = string_list[18] - config_dict["Use FTP"] = string_list[19] - config_dict["Use PHP"] = string_list[20] - config_dict["Download & Exec"] = string_list[25] - config_dict["Bound Files"] = "False" if string_list[24] == "bindfiles" else "True" - else: - config_dict["Use Email"] = string_list[19] - config_dict["Use FTP"] = string_list[20] - config_dict["Use PHP"] = string_list[21] - config_dict["Download & Exec"] = string_list[26] - config_dict["Bound Files"] = "False" if string_list[25] == "bindfiles" else "True" - return config_dict diff --git a/modules/processing/parsers/CAPE/deprecated/_ShadowTech.py b/modules/processing/parsers/CAPE/deprecated/_ShadowTech.py deleted file mode 100644 index 262291ef7de..00000000000 --- a/modules/processing/parsers/CAPE/deprecated/_ShadowTech.py +++ /dev/null @@ -1,117 +0,0 @@ -#!/usr/bin/env python -""" -ShadowTech Config Extractor -""" - -import re -import string - -import createIOC -import database - -new_line = "#-@NewLine@-#" -split_string = "ESILlzCwXBSrQ1Vb72t6bIXtKRzHJkolNNL94gD8hIi9FwLiiVlrznTz68mkaaJQQSxJfdLyE4jCnl5QJJWuPD4NeO4WFYURvmkth8" -enc_key = "pSILlzCwXBSrQ1Vb72t6bIXtKRzAHJklNNL94gD8hIi9FwLiiVlr" # Actual key is "KeY11PWD24" - - -# Helper Functions Go Here - - -def string_print(line): - return [x for x in line if x in string.printable] - - -def get_config(data): - config_list = [] - config_string = data.split(split_string) - for x in range(1, len(config_string)): - try: - output = "" - hex_pairs = [config_string[x][i : i + 2] for i in range(0, len(config_string[x]), 2)] - for i in range(len(config_string[x]) // 2): - data_slice = int(hex_pairs[i], 16) # get next hex value - key_slice = ord(enc_key[i + 1]) # get next Char For Key - output += chr(data_slice ^ key_slice) # xor Hex and Key Char - print(output) - except Exception: - output = "DecodeError" - config_list.append(output) - return config_list - - -# returns pretty config -def parse_config(config_list): - return { - "Domain": config_list[0], - "Port": config_list[1], - "CampaignID": config_list[2], - "Password": config_list[3], - "InstallFlag": config_list[4], - "RegistryKey": config_list[5], - "Melt": config_list[6], - "Persistance": config_list[7], - "Mutex": config_list[8], - "ShowMsgBox": config_list[9], - # "Flag5": config_list[10] # MsgBox Icon, - # "Flag6": config_list[11] # MsgBox Buttons, - "MsgBoxTitle": config_list[12], - "MsgBoxText": config_list[13], - } - - -""" -def decrypt_XOR(enckey, data): - # ToDo fix it yourself, XOR not defined - cipher = XOR.new(enckey) # set the cipher - return cipher.decrypt(data) # decrpyt the data -""" - - -def snortRule(md5, config_dict): - rules = [] - domain = config_dict["Domain"] - ipPattern = re.compile(r"\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}") - ipTest = ipPattern.search(domain) - if len(domain) > 1: - if ipTest: - rules.append( - f"""alert tcp any any -> {domain}""" - f""" any (msg: "ShadowTech Beacon Domain: {domain}""" - """"; classtype:trojan-activity; sid:5000000; rev:1; priority:1; reference:url,http://malwareconfig.com;)""" - ) - else: - rules.append( - f"""alert udp any any -> any 53 (msg: "ShadowTech Beacon Domain: {domain}""" - f""""; content:"|0e|{domain}""" - """|00|"; nocase; classtype:trojan-activity; sid:5000000; rev:1; priority:1; reference:url,http://malwareconfig.com;)""" - ) - rules.append( - f"""alert tcp any any -> any 53 (msg: "ShadowTech Beacon Domain: {domain}""" - f""""; content:"|0e|{domain}""" - """|00|"; nocase; classtype:trojan-activity; sid:5000000; rev:1; priority:1; reference:url,http://malwareconfig.com;)""" - ) - database.insertSnort(md5, rules) - - -# IOC Creator Two elements Domain or install -def generateIOC(md5, config_dict): - items = [ - [ - ("is", "PortItem", "PortItem/remotePort", "string", config_dict["Port"]), - ("contains", "Network", "Network/DNS", "string", config_dict["Domain"]), - ] - ] - IOC = createIOC.main(items, "ShadowTech", md5) - database.insertIOC(md5, IOC) - - -def run(md5, data): - raw_config = get_config(data) - - # lets Process this and format the config - config_dict = parse_config(raw_config) - if len(config_dict["Domain"]) > 0: - snortRule(md5, config_dict) - generateIOC(md5, config_dict) - database.insertDomain(md5, [config_dict["Domain"]]) - return config_dict diff --git a/modules/processing/parsers/CAPE/deprecated/_VirusRat.py b/modules/processing/parsers/CAPE/deprecated/_VirusRat.py deleted file mode 100644 index 108bac4e239..00000000000 --- a/modules/processing/parsers/CAPE/deprecated/_VirusRat.py +++ /dev/null @@ -1,69 +0,0 @@ -import re - -import database -import ioc - - -def run(md5, data): - config_dict = {} - config = data.split("abccba") - if len(config) > 5: - config_dict = { - "Domain": config[1], - "Port": config[2], - "Campaign Name": config[3], - "Copy StartUp": config[4], - "StartUp Name": config[5], - "Add To Registry": config[6], - "Registry Key": config[7], - "Melt + Inject SVCHost": config[8], - "Anti Kill Process": config[9], - "USB Spread": config[10], - "Kill AVG 2012-2013": config[11], - "Kill Process Hacker": config[12], - "Kill Process Explorer": config[13], - "Kill NO-IP": config[14], - "Block Virus Total": config[15], - "Block Virus Scan": config[16], - "HideProcess": config[17], - } - snortRule(md5, config_dict) - createIOC(md5, config_dict) - database.insertDomain(md5, [config_dict["Domain"]]) - return config_dict - - -def snortRule(md5, config_dict): - rules = [] - domain = config_dict["Domain"] - ipPattern = re.compile(r"\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}") - ipTest = ipPattern.search(domain) - if len(domain) > 1: - if ipTest: - rules.append( - f"""alert tcp any any -> {domain}""" - f""" any (msg: "VirusRat Beacon Domain: {domain}""" - """"; classtype:trojan-activity; sid:5000000; rev:1; priority:1; reference:url,http://malwareconfig.com;)""" - ) - else: - rules.append( - f"""alert udp any any -> any 53 (msg: "VirusRat Beacon Domain: {domain}""" - f""""; content:"|0e|{domain}""" - """|00|"; nocase; classtype:trojan-activity; sid:5000000; rev:1; priority:1; reference:url,http://malwareconfig.com;)""", - f"""alert tcp any any -> any 53 (msg: "VirusRat Beacon Domain: {domain}""" - f""""; content:"|0e|{domain}""" - """|00|"; nocase; classtype:trojan-activity; sid:5000000; rev:1; priority:1; reference:url,http://malwareconfig.com;)""", - ) - database.insertSnort(md5, rules) - - -# IOC Creator Two elements Domain or install -def createIOC(md5, config_dict): - items = [ - ("contains", "Network", "Network/DNS", "string", config_dict["Domain"]), - ("is", "PortItem", "PortItem/remotePort", "string", config_dict["Port"]), - ("is", "ProcessItem", "ProcessItem/name", "string", config_dict["StartUp Name"]), - ("is", "RegistryItem", "RegistryItem/Value", "string", config_dict["Registry Key"]), - ] - IOC = ioc.main(items) - database.insertIOC(md5, IOC) diff --git a/modules/processing/parsers/CAPE/deprecated/_jRat.py b/modules/processing/parsers/CAPE/deprecated/_jRat.py deleted file mode 100644 index 3d143a7310e..00000000000 --- a/modules/processing/parsers/CAPE/deprecated/_jRat.py +++ /dev/null @@ -1,196 +0,0 @@ -import re -from base64 import b64decode -from io import StringIO -from zipfile import ZipFile - -import database -from Cryptodome.Cipher import AES, DES3 - - -def run(md5, data): - print("[+] Extracting Data from Jar") - enckey, conf = get_parts(data) - if enckey is None: - return - print(f"[+] Decoding Config with Key: {enckey.encode().hex()}") - if len(enckey) == 16: - # Newer versions use a base64 encoded config.dat - # this is not a great test but should work 99% of the time - decrypt_func = new_aes if "==" in conf else old_aes - raw_config = decrypt_func(conf, enckey) - elif len(enckey) == 32: - raw_config = old_des(conf, enckey) - config_dict = parse_config(raw_config, enckey) - snortRule(md5, config_dict) - database.insertDomain(md5, [config_dict["Domain"]]) - return config_dict - - -# Helper Functions Go Here - - -# This extracts the Encryption Key and Config File from the Jar and or Dropper -def get_parts(data): - new_zip = StringIO(data) - enckey = None - dropper = None - conf = None - try: - with ZipFile(new_zip, "r") as zip: - for name in zip.namelist(): # get all the file names - if name == "key.dat": # this file contains the encrytpion key - enckey = zip.read(name) - elif name == "enc.dat": # if this file exists, jrat has an installer / dropper - dropper = zip.read(name) - elif name == "config.dat": # this is the encrypted config file - conf = zip.read(name) - except Exception: - print(f"[+] Dropped File is not Jar File starts with Hex Chars: {data[:5].encode().hex()}") - return None, None - if enckey and conf: - return enckey, conf - elif enckey and dropper: - newkey, conf = get_dropper(enckey, dropper) - return newkey, conf - return None, None - - -# This extracts the Encryption Key and New conf from a 'Dropper' jar -def get_dropper(enckey, dropper): - split = enckey.split("\x2c") - key = split[0][:16] - print("[+] Dropper Detected") - for x in split: # grab each line of the config and decode it. - try: - drop = b64decode(x).decode("hex") - print(f" [-] {drop}".replace("\x0d\x0a", "")) - except Exception: - drop = b64decode(x[16:]).decode("hex") - print(f" [-] {drop}") - new_zipdata = decrypt_aes(key, dropper) - new_key, conf = get_parts(new_zipdata) - return new_key, conf - - -# Returns only printable chars -def string_print(line): - return "".join((char for char in line if 32 < ord(char) < 127)) - - -# Messy Messy Messy -def messy_split(long_line): - # this is a messy way to split the data but it works for now. - """ - Split on = gives me the right sections but deletes the b64 padding - use modulo math to restore padding. - return new list. - """ - new_list = [] - old_list = long_line.split("=") - for line in old_list: - if len(line) != 0: - line += "=" * ((4 - len(line) % 4) % 4) - new_list.append(line) - return new_list - - -# AES Decrypt -def decrypt_aes(enckey, data): - cipher = AES.new(enckey) # set the cipher - return cipher.decrypt(data) # decrpyt the data - - -# DES Decrypt -def decrypt_des(enckey, data): - cipher = DES3.new(enckey) # set the ciper - return cipher.decrypt(data) # decrpyt the data - - -# Process Versions 3.2.2 > 4.2. -def old_aes(conf, enckey): - decoded_config = decrypt_aes(enckey, conf) - clean_config = string_print(decoded_config) - return clean_config.split("SPLIT") - - -# Process versions 4.2. > -def new_aes(conf, enckey): - sections = messy_split(conf) - decoded_config = "".join(decrypt_aes(enckey, b64decode(x)) for x in sections) - return string_print(decoded_config).split("SPLIT") - - -# process versions < 3.2.2 -def old_des(conf, enckey): - decoded_config = decrypt_des(conf, enckey) - clean_config = string_print(decoded_config) - return clean_config.split("SPLIT") - - -def parse_config(raw_config, enckey): - config_dict = {} - for kv in raw_config: - if kv == "": - continue - kv = string_print(kv) - key, value = kv.split("=") - if key == "ip": - config_dict["Domain"] = value - elif key == "port": - config_dict["Port"] = value - elif key == "os": - config_dict["OS"] = value - elif key == "mport": - config_dict["MPort"] = value - elif key == "perms": - config_dict["Perms"] = value - elif key == "error": - config_dict["Error"] = value - elif key == "reconsec": - config_dict["RetryInterval"] = value - elif key == "ti": - config_dict["TI"] = value - elif key == "pass": - config_dict["Password"] = value - elif key == "id": - config_dict["CampaignID"] = value - elif key == "mutex": - config_dict["Mutex"] = value - elif key == "toms": - config_dict["TimeOut"] = value - elif key == "per": - config_dict["Persistance"] = value - elif key == "name": - config_dict["Name"] = value - elif key == "tiemout": - config_dict["TimeOutFlag"] = value - elif key == "debugmsg": - config_dict["DebugMsg"] = value - config_dict["EncryptionKey"] = enckey - return config_dict - - -def snortRule(md5, conf): - rules = [] - domain = conf["Domain"] - ipPattern = re.compile(r"\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}") - ipTest = ipPattern.search(domain) - if len(domain) > 1: - if ipTest: - rules.append( - f"""alert tcp any any -> {domain}""" - f""" any (msg: "jRat Beacon Domain: {domain}""" - """"; classtype:trojan-activity; sid:5000000; rev:1; priority:1; reference:url,http://malwareconfig.com;)""" - ) - else: - rules.append( - f"""alert udp any any -> any 53 (msg: "jRat Beacon Domain: {domain}""" - f""""; content:"|0e|{domain}""" - """|00|"; nocase; classtype:trojan-activity; sid:5000000; rev:1; priority:1; reference:url,http://malwareconfig.com;)""" - ) - rules.append( - f"""alert tcp any any -> any 53 (msg: "jRat Beacon Domain: {domain}""" - f""""; content:"|0e|{domain}""" - """|00|"; nocase; classtype:trojan-activity; sid:5000000; rev:1; priority:1; reference:url,http://malwareconfig.com;)""" - ) - database.insertSnort(md5, rules) diff --git a/modules/processing/parsers/CAPE/deprecated/unrecom.py b/modules/processing/parsers/CAPE/deprecated/unrecom.py deleted file mode 100644 index bfc02371e8a..00000000000 --- a/modules/processing/parsers/CAPE/deprecated/unrecom.py +++ /dev/null @@ -1,64 +0,0 @@ -import string -import xml.etree.ElementTree as ET -from io import StringIO -from zipfile import ZipFile - -from Cryptodome.Cipher import ARC4 - - -def extract_embedded(zip_data): - raw_embedded = None - archive = StringIO(zip_data) - with ZipFile(archive) as zip: - for name in zip.namelist(): # get all the file names - if name == "load/ID": # contains first part of key - partial_key = zip.read(name) - enckey = f"{partial_key}DESW7OWKEJRU4P2K" # complete key - if name == "load/MANIFEST.MF": # this is the embedded jar - raw_embedded = zip.read(name) - if raw_embedded is None: - return None - # Decrypt the raw file - return ARC4.new(enckey).decrypt(raw_embedded) - - -def parse_embedded(data): - newzipdata = data - # Write new zip file to memory instead of to disk - with StringIO(newzipdata) as newZip: - with ZipFile(newZip) as zip: - for name in zip.namelist(): - if name == "config.xml": # this is the config in clear - config = zip.read(name) - return config - - -def parse_config(config): - xml = [x for x in config if x in string.printable] - root = ET.fromstring(xml) - raw_config = {} - for child in root: - if child.text.startswith("Unrecom"): - raw_config["Version"] = child.text - else: - raw_config[child.attrib["key"]] = child.text - return { - "Version": raw_config["Version"], - "Delay": raw_config["delay"], - "Domain": raw_config["dns"], - "Extension": raw_config["extensionname"], - "Install": raw_config["install"], - "Port1": raw_config["p1"], - "Port2": raw_config["p2"], - "Password": raw_config["password"], - "PluginFolder": raw_config["pluginfoldername"], - "Prefix": raw_config["prefix"], - } - - -def extract_config(data): - embedded = extract_embedded(data) - if embedded is None: - return None - config = parse_embedded(embedded) - return parse_config(config) if config is not None else None diff --git a/modules/processing/parsers/CAPE/deprecated/xRAT.py b/modules/processing/parsers/CAPE/deprecated/xRAT.py deleted file mode 100644 index 34bc46ddca7..00000000000 --- a/modules/processing/parsers/CAPE/deprecated/xRAT.py +++ /dev/null @@ -1,114 +0,0 @@ -import hashlib -import re -from base64 import b64decode - -import pefile -from Cryptodome.Cipher import AES, XOR - - -def string_print(line): - return "".join((char for char in line if 32 < ord(char) < 127)) - - -def parse_config(config_list, ver): - config_dict = {} - if ver == "V1": - config_dict["Version"] = "1.0.x" - config_dict["Domain"] = config_list[1] - config_dict["Port"] = config_list[2] - config_dict["Password"] = config_list[3] - config_dict["CampaignID"] = config_list[4] - config_dict["InstallName"] = config_list[5] - config_dict["HKCUKey"] = config_list[6] - config_dict["InstallDir"] = config_list[7] - config_dict["Flag1"] = config_list[8] - config_dict["Flag2"] = config_list[9] - config_dict["Mutex"] = config_list[10] - if ver == "V2": - config_dict["Version"] = config_list[0] - config_dict["Domain"] = config_list[1] - config_dict["Password"] = config_list[2] - config_dict["InstallSub"] = config_list[3] - config_dict["InstallName"] = config_list[4] - config_dict["Mutex"] = config_list[5] - config_dict["RegistryKey"] = config_list[6] - return config_dict - - -def get_long_line(data): - try: - raw_config = None - pe = pefile.PE(data=data) - for entry in pe.DIRECTORY_ENTRY_RESOURCE.entries: - if str(entry.name) == "RT_RCDATA": - new_dirs = entry.directory - for entry in new_dirs.entries: - if str(entry.name) == "0": - data_rva = entry.directory.entries[0].data.struct.OffsetToData - size = entry.directory.entries[0].data.struct.Size - data = pe.get_memory_mapped_image()[data_rva : data_rva + size] - raw_config = data - except Exception: - raw_config = None - if raw_config is not None: - return raw_config, "V1" - try: - m = re.search("\x69\x00\x6F\x00\x6E\x00\x00\x59(.*)\x6F\x43\x00\x61\x00\x6E", data) - raw_config = m.group(0)[4:-12] - return raw_config, "V2" - except Exception: - return None, None - - -def decrypt_XOR(enckey, data): - cipher = XOR.new(enckey) # set the cipher - return cipher.decrypt(data) # decrpyt the data - - -# decrypt function -def decrypt_aes(enckey, data): - iv = data[:16] - cipher = AES.new(enckey, AES.MODE_CBC, iv) # set the cipher - return cipher.decrypt(data[16:]) # decrpyt the data - - -# converts the enc key to an md5 key -def aes_key(enc_key): - return hashlib.md5(enc_key).hexdigest().decode("hex") - - -# This will split all the b64 encoded strings and the encryption key -def get_parts(long_line): - coded_config = [] - raw_line = long_line - small_lines = raw_line.split("\x00\x00") - for line in small_lines: - new_line = line[1:] if len(line) % 2 == 0 else line[2:] - coded_config.append(new_line.replace("\x00", "")) - return coded_config - - -def extract_config(data): - long_line, ver = get_long_line(data) - if ver is None: - return - config_list = [] - if ver == "V1": - # The way the XOR Cypher was implemented the keys are off by 1. - key1 = "RAT11x" # Used for First level of encryption actual key is 'xRAT11' - key2 = "eY11K" # used for individual sections, actual key is 'KeY11' - key3 = "eY11PWD24K" # used for password section only. Actual key is 'KeY11PWD24' - config = long_line.decode("hex") - first_decode = decrypt_XOR(key1, config) - sections = first_decode.split("|//\\\\|") # Split is |//\\| the extra \\ are for escaping. - for i, section in enumerate(sections): - enc_key = key3 if i == 3 else key2 - config_list.append(decrypt_XOR(enc_key, section.decode("hex"))) - elif ver == "V2": - coded_lines = get_parts(long_line) - enc_key = aes_key(coded_lines[-1]) - for i in range(1, (len(coded_lines) - 1)): - decoded_line = b64decode(coded_lines[i]) - decrypt_line = decrypt_aes(enc_key, decoded_line) - config_list.append(string_print(decrypt_line)) - return parse_config(config_list, ver) diff --git a/modules/processing/parsers/CAPE/test_cape.py b/modules/processing/parsers/CAPE/test_cape.py deleted file mode 100644 index f9190c3c306..00000000000 --- a/modules/processing/parsers/CAPE/test_cape.py +++ /dev/null @@ -1,2 +0,0 @@ -def extract_config(): - pass diff --git a/modules/processing/parsers/MACO/AgentTesla.py b/modules/processing/parsers/MACO/AgentTesla.py deleted file mode 100644 index 04615864ac3..00000000000 --- a/modules/processing/parsers/MACO/AgentTesla.py +++ /dev/null @@ -1,64 +0,0 @@ -import os - -from maco.extractor import Extractor -from maco.model import ExtractorModel as MACOModel - -from modules.processing.parsers.CAPE.AgentTesla import extract_config - - -def convert_to_MACO(raw_config: dict) -> MACOModel: - if not raw_config: - return - - protocol = raw_config.get("Protocol") - if not protocol: - return - - parsed_result = MACOModel(family="AgentTesla", other=raw_config) - if protocol == "Telegram": - parsed_result.http.append(MACOModel.Http(uri=raw_config["C2"], password=raw_config["Password"], usage="c2")) - - elif protocol in ["HTTP(S)", "Discord"]: - parsed_result.http.append(MACOModel.Http(uri=raw_config["C2"], usage="c2")) - - elif protocol == "FTP": - parsed_result.ftp.append( - MACOModel.FTP( - username=raw_config["Username"], - password=raw_config["Password"], - hostname=raw_config["C2"].replace("ftp://", ""), - usage="c2", - ) - ) - - elif protocol == "SMTP": - smtp = dict( - username=raw_config["Username"], - password=raw_config["Password"], - hostname=raw_config["C2"], - mail_to=[raw_config["EmailTo"]], - usage="c2", - ) - if "Port" in raw_config: - smtp["port"] = raw_config["Port"] - parsed_result.smtp.append(MACOModel.SMTP(**smtp)) - - if "Persistence_Filename" in raw_config: - parsed_result.paths.append(MACOModel.Path(path=raw_config["Persistence_Filename"], usage="storage")) - - if "ExternalIPCheckServices" in raw_config: - for service in raw_config["ExternalIPCheckServices"]: - parsed_result.http.append(MACOModel.Http(uri=service, usage="other")) - - return parsed_result - - -class AgentTesla(Extractor): - author = "kevoreilly" - family = "AgentTesla" - last_modified = "2024-10-20" - sharing = "TLP:CLEAR" - yara_rule = open(os.path.join(os.path.dirname(__file__).split("/modules", 1)[0], f"data/yara/CAPE/{family}.yar")).read() - - def run(self, stream, matches): - return convert_to_MACO(extract_config(stream.read())) diff --git a/modules/processing/parsers/MACO/AsyncRAT.py b/modules/processing/parsers/MACO/AsyncRAT.py deleted file mode 100644 index 6f64368cda7..00000000000 --- a/modules/processing/parsers/MACO/AsyncRAT.py +++ /dev/null @@ -1,51 +0,0 @@ -import os - -from maco.extractor import Extractor -from maco.model import ExtractorModel as MACOModel - -from modules.processing.parsers.CAPE.AsyncRAT import extract_config - - -def convert_to_MACO(raw_config: dict) -> MACOModel: - if not raw_config: - return - - parsed_result = MACOModel(family="AsyncRAT", other=raw_config) - - # Mutex - parsed_result.mutex.append(raw_config["Mutex"]) - - # Version - parsed_result.version = raw_config["Version"] - - # Was persistence enabled? - if raw_config["Install"] == "true": - parsed_result.capability_enabled.append("persistence") - else: - parsed_result.capability_disabled.append("persistence") - - # Installation Path - if raw_config.get("Folder"): - parsed_result.paths.append(MACOModel.Path(path=os.path.join(raw_config["Folder"], raw_config["Filename"]), usage="install")) - - # C2s - for i in range(len(raw_config.get("C2s", []))): - parsed_result.http.append(MACOModel.Http(hostname=raw_config["C2s"][i], port=int(raw_config["Ports"][i]), usage="c2")) - # Pastebin - if raw_config.get("Pastebin") not in ["null", None]: - # TODO: Is it used to download the C2 information if not embedded? - # Ref: https://www.netskope.com/blog/asyncrat-using-fully-undetected-downloader - parsed_result.http.append(MACOModel.Http(uri=raw_config["Pastebin"], usage="download")) - - return parsed_result - - -class AsyncRAT(Extractor): - author = "kevoreilly" - family = "AsyncRAT" - last_modified = "2024-10-26" - sharing = "TLP:CLEAR" - yara_rule = open(os.path.join(os.path.dirname(__file__).split("/modules", 1)[0], f"data/yara/CAPE/{family}.yar")).read() - - def run(self, stream, matches): - return convert_to_MACO(extract_config(stream.read())) diff --git a/modules/processing/parsers/MACO/AuroraStealer.py b/modules/processing/parsers/MACO/AuroraStealer.py deleted file mode 100644 index 1a63055f07e..00000000000 --- a/modules/processing/parsers/MACO/AuroraStealer.py +++ /dev/null @@ -1,29 +0,0 @@ -import os - -from maco.extractor import Extractor -from maco.model import ExtractorModel as MACOModel - -from modules.processing.parsers.CAPE.AuroraStealer import extract_config - - -def convert_to_MACO(raw_config: dict): - if not raw_config: - return None - - parsed_result = MACOModel(family="AuroraStealer", other=raw_config) - if raw_config.get("C2"): - # IP related to C2 - parsed_result.http.append(MACOModel.Http(hostname=raw_config["C2"], usage="c2")) - - return parsed_result - - -class AuroraStealer(Extractor): - author = "kevoreilly" - family = "AuroraStealer" - last_modified = "2024-10-26" - sharing = "TLP:CLEAR" - yara_rule = open(os.path.join(os.path.dirname(__file__).split("/modules", 1)[0], f"data/yara/CAPE/{family}.yar")).read() - - def run(self, stream, matches): - return convert_to_MACO(extract_config(stream.read())) diff --git a/modules/processing/parsers/MACO/Azorult.py b/modules/processing/parsers/MACO/Azorult.py deleted file mode 100644 index 4b462eacd74..00000000000 --- a/modules/processing/parsers/MACO/Azorult.py +++ /dev/null @@ -1,22 +0,0 @@ -from maco.extractor import Extractor -from maco.model import ExtractorModel as MACOModel - -from modules.processing.parsers.CAPE.Azorult import extract_config, rule_source - - -def convert_to_MACO(raw_config: dict): - if not raw_config: - return None - - return MACOModel(family="Azorult", http=[MACOModel.Http(hostname=raw_config["address"])], other=raw_config) - - -class Azorult(Extractor): - author = "kevoreilly" - family = "Azorult" - last_modified = "2024-10-26" - sharing = "TLP:CLEAR" - yara_rule = rule_source - - def run(self, stream, matches): - return convert_to_MACO(extract_config(stream.read())) diff --git a/modules/processing/parsers/MACO/BackOffLoader.py b/modules/processing/parsers/MACO/BackOffLoader.py deleted file mode 100644 index 155fe0d8b9a..00000000000 --- a/modules/processing/parsers/MACO/BackOffLoader.py +++ /dev/null @@ -1,33 +0,0 @@ -from maco.extractor import Extractor -from maco.model import ExtractorModel as MACOModel - -from modules.processing.parsers.CAPE.BackOffLoader import extract_config - - -def convert_to_MACO(raw_config: dict): - if not raw_config: - return None - - parsed_result = MACOModel(family="BackOffLoader", other=raw_config) - - # Version - parsed_result.version = raw_config["Version"] - - # Encryption details - parsed_result.encryption.append( - MACOModel.Encryption(algorithm="rc4", key=raw_config["EncryptionKey"], seed=raw_config["RC4Seed"]) - ) - for url in raw_config["URLs"]: - parsed_result.http.append(MACOModel.Http(url=url)) - - return parsed_result - - -class BackOffLoader(Extractor): - author = "kevoreilly" - family = "BackOffLoader" - last_modified = "2024-10-26" - sharing = "TLP:CLEAR" - - def run(self, stream, matches): - return convert_to_MACO(extract_config(stream.read())) diff --git a/modules/processing/parsers/MACO/BackOffPOS.py b/modules/processing/parsers/MACO/BackOffPOS.py deleted file mode 100644 index 2dfd7b89bbd..00000000000 --- a/modules/processing/parsers/MACO/BackOffPOS.py +++ /dev/null @@ -1,33 +0,0 @@ -from maco.extractor import Extractor -from maco.model import ExtractorModel as MACOModel - -from modules.processing.parsers.CAPE.BackOffPOS import extract_config - - -def convert_to_MACO(raw_config: dict): - if not raw_config: - return None - - parsed_result = MACOModel(family="BackOffPOS", other=raw_config) - - # Version - parsed_result.version = raw_config["Version"] - - # Encryption details - parsed_result.encryption.append( - MACOModel.Encryption(algorithm="rc4", key=raw_config["EncryptionKey"], seed=raw_config["RC4Seed"]) - ) - for url in raw_config["URLs"]: - parsed_result.http.append(MACOModel.Http(url=url)) - - return parsed_result - - -class BackOffPOS(Extractor): - author = "kevoreilly" - family = "BackOffPOS" - last_modified = "2024-10-26" - sharing = "TLP:CLEAR" - - def run(self, stream, matches): - return convert_to_MACO(extract_config(stream.read())) diff --git a/modules/processing/parsers/MACO/BitPaymer.py b/modules/processing/parsers/MACO/BitPaymer.py deleted file mode 100644 index 34d0590fb08..00000000000 --- a/modules/processing/parsers/MACO/BitPaymer.py +++ /dev/null @@ -1,29 +0,0 @@ -from maco.extractor import Extractor -from maco.model import ExtractorModel as MACOModel - -from modules.processing.parsers.CAPE.BitPaymer import extract_config, rule_source - - -def convert_to_MACO(raw_config: dict): - if not raw_config: - return None - - parsed_result = MACOModel(family="BitPaymer", other=raw_config) - - # Extracted strings - parsed_result.decoded_strings = raw_config["strings"] - - # Encryption details - parsed_result.encryption.append(MACOModel.Encryption(algorithm="rsa", public_key=raw_config["RSA public key"])) - return parsed_result - - -class BitPaymer(Extractor): - author = "kevoreilly" - family = "BitPaymer" - last_modified = "2024-10-26" - sharing = "TLP:CLEAR" - yara_rule = rule_source - - def run(self, stream, matches): - return convert_to_MACO(extract_config(stream.read())) diff --git a/modules/processing/parsers/MACO/BlackDropper.py b/modules/processing/parsers/MACO/BlackDropper.py deleted file mode 100644 index da619a6cbc4..00000000000 --- a/modules/processing/parsers/MACO/BlackDropper.py +++ /dev/null @@ -1,32 +0,0 @@ -import os - -from maco.extractor import Extractor -from maco.model import ExtractorModel as MACOModel - -from modules.processing.parsers.CAPE.BlackDropper import extract_config - - -def convert_to_MACO(raw_config: dict): - if not raw_config: - return None - - parsed_result = MACOModel(family="BlackDropper", campaign_id=[raw_config["campaign"]], other=raw_config) - - for dir in raw_config.get("directories", []): - parsed_result.paths.append(MACOModel.Path(path=dir)) - - for url in raw_config.get("urls", []): - parsed_result.http.append(MACOModel.Http(uri=url)) - - return parsed_result - - -class BlackDropper(Extractor): - author = "kevoreilly" - family = "BlackDropper" - last_modified = "2024-10-26" - sharing = "TLP:CLEAR" - yara_rule = open(os.path.join(os.path.dirname(__file__).split("/modules", 1)[0], f"data/yara/CAPE/{family}.yar")).read() - - def run(self, stream, matches): - return convert_to_MACO(extract_config(stream.read())) diff --git a/modules/processing/parsers/MACO/BlackNix.py b/modules/processing/parsers/MACO/BlackNix.py deleted file mode 100644 index 70408d7828e..00000000000 --- a/modules/processing/parsers/MACO/BlackNix.py +++ /dev/null @@ -1,66 +0,0 @@ -import os - -from maco.extractor import Extractor -from maco.model import ExtractorModel as MACOModel - -from modules.processing.parsers.CAPE.BlackNix import extract_config - - -def convert_to_MACO(raw_config: dict): - if not raw_config: - return None - - parsed_result = MACOModel(family="BlackNix", other=raw_config) - - # Mutex - parsed_result.mutex.append(raw_config["Mutex"]) - - # Capabilities that are enabled/disabled - # TODO: Review if these are all capabilities set by a boolean flag - for capa in [ - "Anti Sandboxie", - "Kernel Mode Unhooking", - "User Mode Unhooking", - "Melt Server", - "Offline Screen Capture", - "Offline Keylogger", - "Copy to ADS", - "Safe Mode Startup", - "Inject winlogon.exe", - "Active X Run", - "Registry Run", - ]: - if raw_config[capa].lower() == "true": - parsed_result.capability_enabled.append(capa) - else: - parsed_result.capability_disabled.append(capa) - - # Delay Time - parsed_result.sleep_delay = raw_config["Delay Time"] - - # Password - parsed_result.password.append(raw_config["Password"]) - - # C2 Domain - parsed_result.http.append(MACOModel.Http(hostname=raw_config["Domain"], usage="c2")) - # Registry - parsed_result.registry.append(MACOModel.Registry(key=raw_config["Registry Key"])) - - # Install Path - parsed_result.paths.append( - MACOModel.Path(path=os.path.join(raw_config["Install Path"], raw_config["Install Name"]), usage="install") - ) - - # Campaign Group/Name - parsed_result.campaign_id = [raw_config["Campaign Name"], raw_config["Campaign Group"]] - return parsed_result - - -class BlackNix(Extractor): - author = "kevoreilly" - family = "BlackNix" - last_modified = "2024-10-26" - sharing = "TLP:CLEAR" - - def run(self, stream, matches): - return convert_to_MACO(extract_config(stream.read())) diff --git a/modules/processing/parsers/MACO/Blister.py b/modules/processing/parsers/MACO/Blister.py deleted file mode 100644 index 1045539c2bc..00000000000 --- a/modules/processing/parsers/MACO/Blister.py +++ /dev/null @@ -1,36 +0,0 @@ -import os - -from maco.extractor import Extractor -from maco.model import ExtractorModel as MACOModel - -from modules.processing.parsers.CAPE.Blister import extract_config - - -def convert_to_MACO(raw_config: dict): - if not raw_config: - return None - - parsed_result = MACOModel(family="Blister", other=raw_config) - - for capa in ["Persistence", "Sleep after injection"]: - if raw_config[capa]: - parsed_result.capability_enabled.append(capa) - else: - parsed_result.capability_disabled.append(capa) - - # Rabbit encryption - parsed_result.encryption.append( - MACOModel.Encryption(algorithm="rabbit", key=raw_config["Rabbit key"], iv=raw_config["Rabbit IV"]) - ) - return parsed_result - - -class Blister(Extractor): - author = "kevoreilly" - family = "Blister" - last_modified = "2024-10-26" - sharing = "TLP:CLEAR" - yara_rule = open(os.path.join(os.path.dirname(__file__).split("/modules", 1)[0], f"data/yara/CAPE/{family}.yar")).read() - - def run(self, stream, matches): - return convert_to_MACO(extract_config(stream.read())) diff --git a/modules/processing/parsers/MACO/BruteRatel.py b/modules/processing/parsers/MACO/BruteRatel.py deleted file mode 100644 index bfd7e32fda4..00000000000 --- a/modules/processing/parsers/MACO/BruteRatel.py +++ /dev/null @@ -1,32 +0,0 @@ -import os - -from maco.extractor import Extractor -from maco.model import ExtractorModel as MACOModel - -from modules.processing.parsers.CAPE.BruteRatel import extract_config - - -def convert_to_MACO(raw_config: dict): - if not raw_config: - return None - - parsed_result = MACOModel(family="BruteRatel", other=raw_config) - - for url in raw_config["C2"]: - for path in raw_config["URI"]: - parsed_result.http.append( - MACOModel.Http(uri=url, user_agent=raw_config["User Agent"], port=raw_config["Port"], path=path, usage="c2") - ) - - return parsed_result - - -class BruteRatel(Extractor): - author = "kevoreilly" - family = "BruteRatel" - last_modified = "2024-10-26" - sharing = "TLP:CLEAR" - yara_rule = open(os.path.join(os.path.dirname(__file__).split("/modules", 1)[0], f"data/yara/CAPE/{family}.yar")).read() - - def run(self, stream, matches): - return convert_to_MACO(extract_config(stream.read())) diff --git a/modules/processing/parsers/MACO/BuerLoader.py b/modules/processing/parsers/MACO/BuerLoader.py deleted file mode 100644 index fdda64590ae..00000000000 --- a/modules/processing/parsers/MACO/BuerLoader.py +++ /dev/null @@ -1,28 +0,0 @@ -import os - -from maco.extractor import Extractor -from maco.model import ExtractorModel as MACOModel - -from modules.processing.parsers.CAPE.BuerLoader import extract_config - - -def convert_to_MACO(raw_config: dict): - if not raw_config: - return None - - parsed_result = MACOModel(family="BuerLoader", other=raw_config) - - for c2 in raw_config["address"]: - parsed_result.http.append(MACOModel.Http(hostname=c2, usage="c2")) - return parsed_result - - -class BuerLoader(Extractor): - author = "kevoreilly" - family = "BuerLoader" - last_modified = "2024-10-26" - sharing = "TLP:CLEAR" - yara_rule = open(os.path.join(os.path.dirname(__file__).split("/modules", 1)[0], f"data/yara/CAPE/{family}.yar")).read() - - def run(self, stream, matches): - return convert_to_MACO(extract_config(stream.read())) diff --git a/modules/processing/parsers/MACO/BumbleBee.py b/modules/processing/parsers/MACO/BumbleBee.py deleted file mode 100644 index 27fa023e9e6..00000000000 --- a/modules/processing/parsers/MACO/BumbleBee.py +++ /dev/null @@ -1,46 +0,0 @@ -import os - -from maco.extractor import Extractor -from maco.model import ExtractorModel as MACOModel - -from modules.processing.parsers.CAPE.BumbleBee import extract_config - - -def convert_to_MACO(raw_config: dict): - if not raw_config: - return None - - parsed_result = MACOModel(family="BumbleBee", other=raw_config) - - # Campaign ID - if raw_config.get("Campaign ID"): - parsed_result.campaign_id.append(raw_config["Campaign ID"]) - - # Botnet ID - if raw_config.get("Botnet ID"): - parsed_result.identifier.append(raw_config["Botnet ID"]) - - # C2s - for c2 in raw_config.get("C2s", []): - parsed_result.http.append(MACOModel.Http(hostname=c2, usage="c2")) - - # Data - if raw_config.get("Data"): - parsed_result.binaries.append(MACOModel.Binary(data=raw_config["Data"])) - - # RC4 Key - if raw_config.get("RC4 Key"): - parsed_result.encryption.append(MACOModel.Encryption(algorithm="rc4", key=raw_config["RC4 Key"])) - - return parsed_result - - -class BumbleBee(Extractor): - author = "kevoreilly" - family = "BumbleBee" - last_modified = "2024-10-26" - sharing = "TLP:CLEAR" - yara_rule = open(os.path.join(os.path.dirname(__file__).split("/modules", 1)[0], f"data/yara/CAPE/{family}.yar")).read() - - def run(self, stream, matches): - return convert_to_MACO(extract_config(stream.read())) diff --git a/modules/processing/parsers/MACO/Carbanak.py b/modules/processing/parsers/MACO/Carbanak.py deleted file mode 100644 index 8df0573348b..00000000000 --- a/modules/processing/parsers/MACO/Carbanak.py +++ /dev/null @@ -1,45 +0,0 @@ -from maco.extractor import Extractor -from maco.model import ExtractorModel as MACOModel - -from modules.processing.parsers.CAPE.Carbanak import extract_config, rule_source - - -def convert_to_MACO(raw_config: dict): - if not raw_config: - return None - - parsed_result = MACOModel(family="Carbanak", other=raw_config) - - # Version - if raw_config.get("Version"): - parsed_result.version = raw_config["Version"] - - # Unknown strings - for i in [1, 2]: - if raw_config.get(f"Unknown {i}"): - parsed_result.decoded_strings.append(raw_config[f"Unknown {i}"]) - - # C2 - if raw_config.get("C2"): - if isinstance(raw_config["C2"], str): - parsed_result.http.append(MACOModel.Http(hostname=raw_config["C2"], usage="c2")) - else: - for c2 in raw_config["C2"]: - parsed_result.http.append(MACOModel.Http(hostname=c2, usage="c2")) - - # Campaign Id - if raw_config.get("Campaign Id"): - parsed_result.campaign_id.append(raw_config["Campaign Id"]) - - return parsed_result - - -class Carbanak(Extractor): - author = "kevoreilly" - family = "Carbanak" - last_modified = "2024-10-26" - sharing = "TLP:CLEAR" - yara_rule = rule_source - - def run(self, stream, matches): - return convert_to_MACO(extract_config(stream.read())) diff --git a/modules/processing/parsers/MACO/ChChes.py b/modules/processing/parsers/MACO/ChChes.py deleted file mode 100644 index 02977e00e33..00000000000 --- a/modules/processing/parsers/MACO/ChChes.py +++ /dev/null @@ -1,28 +0,0 @@ -from maco.extractor import Extractor -from maco.model import ExtractorModel as MACOModel - -from modules.processing.parsers.CAPE.ChChes import extract_config, rule_source - - -def convert_to_MACO(raw_config: dict): - if not raw_config: - return None - - parsed_result = MACOModel(family="ChChes", other=raw_config) - - # C2 URLs - for c2_url in raw_config.get("c2_url", []): - parsed_result.http.append(MACOModel.Http(uri=c2_url, usage="c2")) - - return parsed_result - - -class ChChes(Extractor): - author = "kevoreilly" - family = "ChChes" - last_modified = "2024-10-26" - sharing = "TLP:CLEAR" - yara_rule = rule_source - - def run(self, stream, matches): - return convert_to_MACO(extract_config(stream.read())) diff --git a/modules/processing/parsers/MACO/CobaltStrikeBeacon.py b/modules/processing/parsers/MACO/CobaltStrikeBeacon.py deleted file mode 100644 index f639cbb9cc8..00000000000 --- a/modules/processing/parsers/MACO/CobaltStrikeBeacon.py +++ /dev/null @@ -1,50 +0,0 @@ -import os - -from maco.extractor import Extractor -from maco.model import ExtractorModel as MACOModel - -from modules.processing.parsers.CAPE.CobaltStrikeBeacon import extract_config - - -def convert_to_MACO(raw_config: dict): - if not raw_config: - return None - - parsed_result = MACOModel(family="CobaltStrikeBeacon", other=raw_config) - - clean_config = {k: v for k, v in raw_config.items() if v != "Not Found"} - capabilities = {k[1:]: clean_config.pop(k) for k in list(clean_config.keys()) if clean_config[k] in ["True", "False"]} - - for capability, enabled in capabilities.items(): - if enabled.lower() == "true": - parsed_result.capability_enabled.append(capability) - else: - parsed_result.capability_disabled.append(capability) - - if "C2Server" in clean_config: - host, get_path = clean_config.pop("C2Server").split(",") - port = clean_config.pop("Port") - parsed_result.http.append(MACOModel.Http(hostname=host, port=port, method="GET", path=get_path, usage="c2")) - parsed_result.http.append( - MACOModel.Http(hostname=host, port=port, method="POST", path=clean_config.pop("HttpPostUri"), usage="c2") - ) - - parsed_result.sleep_delay = clean_config.pop("SleepTime") - parsed_result.sleep_delay_jitter = clean_config.pop("Jitter") - - for path_key in ["Spawnto_x86", "Spawnto_x64"]: - if path_key in clean_config: - parsed_result.paths.append(MACOModel.Path(path=clean_config.pop(path_key))) - - return parsed_result - - -class CobaltStrikeBeacon(Extractor): - author = "kevoreilly" - family = "CobaltStrikeBeacon" - last_modified = "2024-10-26" - sharing = "TLP:CLEAR" - yara_rule = open(os.path.join(os.path.dirname(__file__).split("/modules", 1)[0], f"data/yara/CAPE/{family}.yar")).read() - - def run(self, stream, matches): - return convert_to_MACO(extract_config(stream.read())) diff --git a/modules/processing/parsers/MACO/CobaltStrikeStager.py b/modules/processing/parsers/MACO/CobaltStrikeStager.py deleted file mode 100644 index 3d3759a0503..00000000000 --- a/modules/processing/parsers/MACO/CobaltStrikeStager.py +++ /dev/null @@ -1,26 +0,0 @@ -import os - -from maco.extractor import Extractor -from maco.model import ExtractorModel as MACOModel - -from modules.processing.parsers.CAPE.CobaltStrikeStager import extract_config - - -def convert_to_MACO(raw_config: dict): - if not raw_config: - return None - - parsed_result = MACOModel(family="CobaltStrikeStager", other=raw_config) - - return parsed_result - - -class CobaltStrikeStager(Extractor): - author = "kevoreilly" - family = "CobaltStrikeStager" - last_modified = "2024-10-26" - sharing = "TLP:CLEAR" - yara_rule = open(os.path.join(os.path.dirname(__file__).split("/modules", 1)[0], f"data/yara/CAPE/{family}.yar")).read() - - def run(self, stream, matches): - return convert_to_MACO(extract_config(stream.read())) diff --git a/modules/processing/parsers/MACO/DCRat.py b/modules/processing/parsers/MACO/DCRat.py deleted file mode 100644 index fba00548801..00000000000 --- a/modules/processing/parsers/MACO/DCRat.py +++ /dev/null @@ -1,27 +0,0 @@ -import os - -from maco.extractor import Extractor -from maco.model import ExtractorModel as MACOModel - -from modules.processing.parsers.CAPE.DCRat import extract_config - - -def convert_to_MACO(raw_config: dict): - if not raw_config: - return None - - # TODO: Assign fields to MACO model - parsed_result = MACOModel(family="DCRat", other=raw_config) - - return parsed_result - - -class DCRat(Extractor): - author = "kevoreilly" - family = "DCRat" - last_modified = "2024-10-26" - sharing = "TLP:CLEAR" - yara_rule = open(os.path.join(os.path.dirname(__file__).split("/modules", 1)[0], f"data/yara/CAPE/{family}.yar")).read() - - def run(self, stream, matches): - return convert_to_MACO(extract_config(stream.read())) diff --git a/modules/processing/parsers/MACO/DarkGate.py b/modules/processing/parsers/MACO/DarkGate.py deleted file mode 100644 index 6d382f80cd0..00000000000 --- a/modules/processing/parsers/MACO/DarkGate.py +++ /dev/null @@ -1,52 +0,0 @@ -import os -from copy import deepcopy - -from maco.extractor import Extractor -from maco.model import ExtractorModel as MACOModel - -from modules.processing.parsers.CAPE.DarkGate import extract_config - - -def convert_to_MACO(raw_config: dict): - if not raw_config: - return None - - parsed_result = MACOModel(family="DarkGate", other=raw_config) - - # Create a copy of the raw configuration for parsing - config = deepcopy(raw_config) - - # Go through capabilities/settings that are boolean in nature - for k, v in list(config.items()): - if v not in ["Yes", "No"]: - continue - - if v == "Yes": - parsed_result.capability_enabled.append(k) - else: - parsed_result.capability_disabled.append(k) - - # Remove key from raw config - config.pop(k) - - # C2 - c2_port = config.pop("c2_port", None) - for c2_url in config.pop("C2", []): - parsed_result.http.append(MACOModel.Http(uri=c2_url, port=c2_port, usage="c2")) - - # Mutex - if config.get("internal_mutex"): - parsed_result.mutex.append(config.pop("internal_mutex")) - - return parsed_result - - -class DarkGate(Extractor): - author = "kevoreilly" - family = "DarkGate" - last_modified = "2024-10-26" - sharing = "TLP:CLEAR" - yara_rule = open(os.path.join(os.path.dirname(__file__).split("/modules", 1)[0], f"data/yara/CAPE/{family}.yar")).read() - - def run(self, stream, matches): - return convert_to_MACO(extract_config(stream.read())) diff --git a/modules/processing/parsers/MACO/DoppelPaymer.py b/modules/processing/parsers/MACO/DoppelPaymer.py deleted file mode 100644 index 1e1d97a8b43..00000000000 --- a/modules/processing/parsers/MACO/DoppelPaymer.py +++ /dev/null @@ -1,30 +0,0 @@ -from maco.extractor import Extractor -from maco.model import ExtractorModel as MACOModel - -from modules.processing.parsers.CAPE.DoppelPaymer import extract_config, rule_source - - -def convert_to_MACO(raw_config: dict): - if not raw_config: - return None - - parsed_result = MACOModel(family="DoppelPaymer") - - if "strings" in raw_config: - parsed_result.decoded_strings = raw_config["strings"] - - if "RSA public key" in raw_config: - parsed_result.encryption.append(MACOModel.Encryption(algorithm="RSA", public_key=raw_config["RSA public key"])) - - return parsed_result - - -class DoppelPaymer(Extractor): - author = "kevoreilly" - family = "DoppelPaymer" - last_modified = "2024-10-26" - sharing = "TLP:CLEAR" - yara_rule = rule_source - - def run(self, stream, matches): - return convert_to_MACO(extract_config(stream.read())) diff --git a/modules/processing/parsers/MACO/DridexLoader.py b/modules/processing/parsers/MACO/DridexLoader.py deleted file mode 100644 index 7a1097ab71a..00000000000 --- a/modules/processing/parsers/MACO/DridexLoader.py +++ /dev/null @@ -1,33 +0,0 @@ -from maco.extractor import Extractor -from maco.model import ExtractorModel as MACOModel - -from modules.processing.parsers.CAPE.DridexLoader import extract_config, rule_source - - -def convert_to_MACO(raw_config: dict): - if not raw_config: - return None - - parsed_result = MACOModel(family="DridexLoader", other=raw_config) - - for c2_address in raw_config.get("address", []): - parsed_result.http.append(MACOModel.Http(uri=c2_address, usage="c2")) - - if "RC4 key" in raw_config: - parsed_result.encryption.append(MACOModel.Encryption(algorithm="RC4", key=raw_config["RC4 key"])) - - if "Botnet ID" in raw_config: - parsed_result.identifier.append(raw_config["Botnet ID"]) - - return parsed_result - - -class DridexLoader(Extractor): - author = "kevoreilly" - family = "DridexLoader" - last_modified = "2024-10-26" - sharing = "TLP:CLEAR" - yara_rule = rule_source - - def run(self, stream, matches): - return convert_to_MACO(extract_config(stream.read())) diff --git a/modules/processing/parsers/MACO/Emotet.py b/modules/processing/parsers/MACO/Emotet.py deleted file mode 100644 index 6cc29da2b0b..00000000000 --- a/modules/processing/parsers/MACO/Emotet.py +++ /dev/null @@ -1,32 +0,0 @@ -from maco.extractor import Extractor -from maco.model import ExtractorModel as MACOModel - -from modules.processing.parsers.CAPE.Emotet import extract_config, rule_source - - -def convert_to_MACO(raw_config: dict): - if not raw_config: - return None - - parsed_result = MACOModel(family="Emotet", other=raw_config) - - for c2_address in raw_config.get("address", []): - parsed_result.http.append(MACOModel.Http(uri=c2_address, usage="c2")) - - if "RC4 public key" in raw_config: - parsed_result.encryption.append(MACOModel.Encryption(algorithm="RC4", public_key=raw_config["RSA public key"])) - - parsed_result.other = {k: raw_config[k] for k in raw_config.keys() if k not in ["address", "RSA public key"]} - - return parsed_result - - -class Emotet(Extractor): - author = "kevoreilly" - family = "Emotet" - last_modified = "2024-10-26" - sharing = "TLP:CLEAR" - yara_rule = rule_source - - def run(self, stream, matches): - return convert_to_MACO(extract_config(stream.read())) diff --git a/modules/processing/parsers/MACO/Enfal.py b/modules/processing/parsers/MACO/Enfal.py deleted file mode 100644 index 8fe4d6f2ff6..00000000000 --- a/modules/processing/parsers/MACO/Enfal.py +++ /dev/null @@ -1,25 +0,0 @@ -from maco.extractor import Extractor -from maco.model import ExtractorModel as MACOModel - -from modules.processing.parsers.CAPE.Enfal import extract_config, rule_source - - -def convert_to_MACO(raw_config: dict): - if not raw_config: - return None - - # TODO: Assign fields to MACO model - parsed_result = MACOModel(family="Enfal", other=raw_config) - - return parsed_result - - -class Enfal(Extractor): - author = "kevoreilly" - family = "Enfal" - last_modified = "2024-10-26" - sharing = "TLP:CLEAR" - yara_rule = rule_source - - def run(self, stream, matches): - return convert_to_MACO(extract_config(stream.read())) diff --git a/modules/processing/parsers/MACO/EvilGrab.py b/modules/processing/parsers/MACO/EvilGrab.py deleted file mode 100644 index e32975f06bc..00000000000 --- a/modules/processing/parsers/MACO/EvilGrab.py +++ /dev/null @@ -1,38 +0,0 @@ -from maco.extractor import Extractor -from maco.model import ExtractorModel as MACOModel - -from modules.processing.parsers.CAPE.EvilGrab import extract_config, rule_source - - -def convert_to_MACO(raw_config: dict): - if not raw_config: - return None - - parsed_result = MACOModel(family="EvilGrab", other=raw_config) - - if "mutex" in raw_config: - parsed_result.mutex.append(raw_config["mutex"]) - - if "missionid" in raw_config: - parsed_result.campaign_id.append(raw_config["missionid"]) - - if "version" in raw_config: - parsed_result.version = raw_config["version"] - - if "c2_address" in raw_config: - parsed_result.http.append( - parsed_result.Http(uri=raw_config["c2_address"], port=raw_config["port"][0] if "port" in raw_config else None) - ) - - return parsed_result - - -class EvilGrab(Extractor): - author = "kevoreilly" - family = "EvilGrab" - last_modified = "2024-10-26" - sharing = "TLP:CLEAR" - yara_rule = rule_source - - def run(self, stream, matches): - return convert_to_MACO(extract_config(stream.read())) diff --git a/modules/processing/parsers/MACO/Fareit.py b/modules/processing/parsers/MACO/Fareit.py deleted file mode 100644 index d09c1492600..00000000000 --- a/modules/processing/parsers/MACO/Fareit.py +++ /dev/null @@ -1,27 +0,0 @@ -import os - -from maco.extractor import Extractor -from maco.model import ExtractorModel as MACOModel - -from modules.processing.parsers.CAPE.Fareit import extract_config - - -def convert_to_MACO(raw_config: dict): - if not raw_config: - return None - - # TODO: Assign fields to MACO model - parsed_result = MACOModel(family="Fareit", other=raw_config) - - return parsed_result - - -class Fareit(Extractor): - author = "kevoreilly" - family = "Fareit" - last_modified = "2024-10-26" - sharing = "TLP:CLEAR" - yara_rule = open(os.path.join(os.path.dirname(__file__).split("/modules", 1)[0], f"data/yara/CAPE/{family}.yar")).read() - - def run(self, stream, matches): - return convert_to_MACO(extract_config(stream.read())) diff --git a/modules/processing/parsers/MACO/Formbook.py b/modules/processing/parsers/MACO/Formbook.py deleted file mode 100644 index 73a2d4dae8c..00000000000 --- a/modules/processing/parsers/MACO/Formbook.py +++ /dev/null @@ -1,32 +0,0 @@ -import os - -from maco.extractor import Extractor -from maco.model import ExtractorModel as MACOModel - -from modules.processing.parsers.CAPE.Formbook import extract_config - - -def convert_to_MACO(raw_config: dict): - if not raw_config: - return None - - parsed_result = MACOModel(family="Formbook", other=raw_config) - - if "C2" in raw_config: - parsed_result.http.append(MACOModel.Http(uri=raw_config["C2"], usage="c2")) - - for decoy in raw_config.get("Decoys", []): - parsed_result.http.append(MACOModel.Http(uri=decoy, usage="decoy")) - - return parsed_result - - -class Formbook(Extractor): - author = "kevoreilly" - family = "Formbook" - last_modified = "2024-10-26" - sharing = "TLP:CLEAR" - yara_rule = open(os.path.join(os.path.dirname(__file__).split("/modules", 1)[0], f"data/yara/CAPE/{family}.yar")).read() - - def run(self, stream, matches): - return convert_to_MACO(extract_config(stream.read())) diff --git a/modules/processing/parsers/MACO/Greame.py b/modules/processing/parsers/MACO/Greame.py deleted file mode 100644 index bb06c40646c..00000000000 --- a/modules/processing/parsers/MACO/Greame.py +++ /dev/null @@ -1,23 +0,0 @@ -from maco.extractor import Extractor -from maco.model import ExtractorModel as MACOModel - -from modules.processing.parsers.CAPE.Greame import extract_config - - -def convert_to_MACO(raw_config: dict): - if not raw_config: - return None - - parsed_result = MACOModel(family="Greame", other=raw_config) - - return parsed_result - - -class Greame(Extractor): - author = "kevoreilly" - family = "Greame" - last_modified = "2024-10-26" - sharing = "TLP:CLEAR" - - def run(self, stream, matches): - return convert_to_MACO(extract_config(stream.read())) diff --git a/modules/processing/parsers/MACO/GuLoader.py b/modules/processing/parsers/MACO/GuLoader.py deleted file mode 100644 index e0a0ceae0e2..00000000000 --- a/modules/processing/parsers/MACO/GuLoader.py +++ /dev/null @@ -1,29 +0,0 @@ -import os - -from maco.extractor import Extractor -from maco.model import ExtractorModel as MACOModel - -from modules.processing.parsers.CAPE.GuLoader import extract_config - - -def convert_to_MACO(raw_config: dict): - if not raw_config: - return None - - parsed_result = MACOModel(family="GuLoader", other=raw_config) - - for url in raw_config.get("URLs", []): - parsed_result.http.append(MACOModel.Http(uri=url, usage="download")) - - return parsed_result - - -class GuLoader(Extractor): - author = "kevoreilly" - family = "GuLoader" - last_modified = "2024-10-26" - sharing = "TLP:CLEAR" - yara_rule = open(os.path.join(os.path.dirname(__file__).split("/modules", 1)[0], "data/yara/CAPE/Guloader.yar")).read() - - def run(self, stream, matches): - return convert_to_MACO(extract_config(stream.read())) diff --git a/modules/processing/parsers/MACO/Hancitor.py b/modules/processing/parsers/MACO/Hancitor.py deleted file mode 100644 index 1a9add97f8b..00000000000 --- a/modules/processing/parsers/MACO/Hancitor.py +++ /dev/null @@ -1,32 +0,0 @@ -import os - -from maco.extractor import Extractor -from maco.model import ExtractorModel as MACOModel - -from modules.processing.parsers.CAPE.Hancitor import extract_config - - -def convert_to_MACO(raw_config: dict): - if not raw_config: - return None - - parsed_result = MACOModel(family="Hancitor", other=raw_config) - - for url in raw_config.get("address", []): - parsed_result.http.append(MACOModel.Http(uri=url, usage="c2")) - - if "Build ID" in raw_config: - parsed_result.identifier.append(raw_config["Build ID"]) - - return parsed_result - - -class Hancitor(Extractor): - author = "kevoreilly" - family = "Hancitor" - last_modified = "2024-10-26" - sharing = "TLP:CLEAR" - yara_rule = open(os.path.join(os.path.dirname(__file__).split("/modules", 1)[0], f"data/yara/CAPE/{family}.yar")).read() - - def run(self, stream, matches): - return convert_to_MACO(extract_config(stream.read())) diff --git a/modules/processing/parsers/MACO/HttpBrowser.py b/modules/processing/parsers/MACO/HttpBrowser.py deleted file mode 100644 index 6b851fd0178..00000000000 --- a/modules/processing/parsers/MACO/HttpBrowser.py +++ /dev/null @@ -1,35 +0,0 @@ -from maco.extractor import Extractor -from maco.model import ExtractorModel as MACOModel - -from modules.processing.parsers.CAPE.HttpBrowser import extract_config, rule_source - - -def convert_to_MACO(raw_config: dict): - if not raw_config: - return None - - parsed_result = MACOModel(family="HttpBrowser", other=raw_config) - - port = raw_config["port"][0] if "port" in raw_config else None - - if "c2_address" in raw_config: - parsed_result.http.append(MACOModel.Http(uri=raw_config["c2_address"], port=port, usage="c2")) - - if "filepath" in raw_config: - parsed_result.paths.append(MACOModel.Path(path=raw_config["filepath"])) - - if "injectionprocess" in raw_config: - parsed_result["injectionprocess"] = raw_config["injectionprocess"] - - return parsed_result - - -class HttpBrowser(Extractor): - author = "kevoreilly" - family = "HttpBrowser" - last_modified = "2024-10-26" - sharing = "TLP:CLEAR" - yara_rule = rule_source - - def run(self, stream, matches): - return convert_to_MACO(extract_config(stream.read())) diff --git a/modules/processing/parsers/MACO/IcedID.py b/modules/processing/parsers/MACO/IcedID.py deleted file mode 100644 index 5ef0778118a..00000000000 --- a/modules/processing/parsers/MACO/IcedID.py +++ /dev/null @@ -1,24 +0,0 @@ -import os - -from maco.extractor import Extractor -from maco.model import ExtractorModel as MACOModel - -from modules.processing.parsers.CAPE.IcedID import extract_config - - -def convert_to_MACO(raw_config: dict): - if not raw_config: - return None - - return MACOModel(**raw_config) - - -class IcedID(Extractor): - author = "kevoreilly" - family = "IcedID" - last_modified = "2024-10-26" - sharing = "TLP:CLEAR" - yara_rule = open(os.path.join(os.path.dirname(__file__).split("/modules", 1)[0], f"data/yara/CAPE/{family}.yar")).read() - - def run(self, stream, matches): - return convert_to_MACO(extract_config(stream.read())) diff --git a/modules/processing/parsers/MACO/IcedIDLoader.py b/modules/processing/parsers/MACO/IcedIDLoader.py deleted file mode 100644 index 46c6ea4cad4..00000000000 --- a/modules/processing/parsers/MACO/IcedIDLoader.py +++ /dev/null @@ -1,32 +0,0 @@ -import os - -from maco.extractor import Extractor -from maco.model import ExtractorModel as MACOModel - -from modules.processing.parsers.CAPE.IcedIDLoader import extract_config - - -def convert_to_MACO(raw_config: dict): - if not raw_config: - return None - - parsed_result = MACOModel(family="IcedIDLoader", other=raw_config) - - if "C2" in raw_config: - parsed_result.http.append(MACOModel.Http(hostname=raw_config["C2"], usage="c2")) - - if "Campaign" in raw_config: - parsed_result.campaign_id.append(str(raw_config["Campaign"])) - - return parsed_result - - -class IcedIDLoader(Extractor): - author = "kevoreilly" - family = "IcedIDLoader" - last_modified = "2024-10-26" - sharing = "TLP:CLEAR" - yara_rule = open(os.path.join(os.path.dirname(__file__).split("/modules", 1)[0], f"data/yara/CAPE/{family}.yar")).read() - - def run(self, stream, matches): - return convert_to_MACO(extract_config(stream.read())) diff --git a/modules/processing/parsers/MACO/KoiLoader.py b/modules/processing/parsers/MACO/KoiLoader.py deleted file mode 100644 index 63c0c75134d..00000000000 --- a/modules/processing/parsers/MACO/KoiLoader.py +++ /dev/null @@ -1,27 +0,0 @@ -from maco.extractor import Extractor -from maco.model import ExtractorModel as MACOModel - -from modules.processing.parsers.CAPE.KoiLoader import RULE_SOURCE, extract_config - - -def convert_to_MACO(raw_config: dict): - if not raw_config: - return None - - parsed_result = MACOModel(family="KoiLoader", other=raw_config) - - for c2_url in raw_config.get("C2", []): - parsed_result.http.append(MACOModel.Http(uri=c2_url, usage="c2")) - - return parsed_result - - -class KoiLoader(Extractor): - author = "kevoreilly" - family = "KoiLoader" - last_modified = "2024-10-26" - sharing = "TLP:CLEAR" - yara_rule = RULE_SOURCE - - def run(self, stream, matches): - return convert_to_MACO(extract_config(stream.read())) diff --git a/modules/processing/parsers/MACO/Latrodectus.py b/modules/processing/parsers/MACO/Latrodectus.py deleted file mode 100644 index 4ad7cbd1515..00000000000 --- a/modules/processing/parsers/MACO/Latrodectus.py +++ /dev/null @@ -1,44 +0,0 @@ -import os - -from maco.extractor import Extractor -from maco.model import ExtractorModel as MACOModel - -from modules.processing.parsers.CAPE.Latrodectus import extract_config - - -def convert_to_MACO(raw_config: dict): - if not raw_config: - return None - - parsed_result = MACOModel(family="Latrodectus", other=raw_config) - - for c2_url in raw_config.get("C2", []): - parsed_result.http.append(MACOModel.Http(uri=c2_url, usage="c2")) - - if "Group name" in raw_config: - parsed_result.identifier.append(raw_config["Group name"]) - - if "Campaign ID" in raw_config: - parsed_result.campaign_id.append(str(raw_config["Campaign ID"])) - - if "Version" in raw_config: - parsed_result.version = raw_config["Version"] - - if "RC4 key" in raw_config: - parsed_result.encryption.append(MACOModel.Encryption(algorithm="RC4", key=raw_config["RC4 key"])) - - if "Strings" in raw_config: - parsed_result.decoded_strings = raw_config["Strings"] - - return parsed_result - - -class Latrodectus(Extractor): - author = "kevoreilly" - family = "Latrodectus" - last_modified = "2024-10-26" - sharing = "TLP:CLEAR" - yara_rule = open(os.path.join(os.path.dirname(__file__).split("/modules", 1)[0], f"data/yara/CAPE/{family}.yar")).read() - - def run(self, stream, matches): - return convert_to_MACO(extract_config(stream.read())) diff --git a/modules/processing/parsers/MACO/LokiBot.py b/modules/processing/parsers/MACO/LokiBot.py deleted file mode 100644 index 01d36594953..00000000000 --- a/modules/processing/parsers/MACO/LokiBot.py +++ /dev/null @@ -1,29 +0,0 @@ -import os - -from maco.extractor import Extractor -from maco.model import ExtractorModel as MACOModel - -from modules.processing.parsers.CAPE.LokiBot import extract_config - - -def convert_to_MACO(raw_config: dict): - if not raw_config: - return None - - parsed_result = MACOModel(family="LokiBot", other=raw_config) - - for address in raw_config.get("address", []): - parsed_result.http.append(MACOModel.Http(uri=address)) - - return parsed_result - - -class LokiBot(Extractor): - author = "kevoreilly" - family = "LokiBot" - last_modified = "2024-10-26" - sharing = "TLP:CLEAR" - yara_rule = open(os.path.join(os.path.dirname(__file__).split("/modules", 1)[0], f"data/yara/CAPE/{family}.yar")).read() - - def run(self, stream, matches): - return convert_to_MACO(extract_config(stream.read())) diff --git a/modules/processing/parsers/MACO/Lumma.py b/modules/processing/parsers/MACO/Lumma.py deleted file mode 100644 index 5f5153c0b5c..00000000000 --- a/modules/processing/parsers/MACO/Lumma.py +++ /dev/null @@ -1,29 +0,0 @@ -import os - -from maco.extractor import Extractor -from maco.model import ExtractorModel as MACOModel - -from modules.processing.parsers.CAPE.Lumma import extract_config - - -def convert_to_MACO(raw_config: dict): - if not raw_config: - return None - - parsed_result = MACOModel(family="Lumma", other=raw_config) - - for address in raw_config.get("C2", []): - parsed_result.http.append(MACOModel.Http(hostname=address, usage="c2")) - - return parsed_result - - -class Lumma(Extractor): - author = "kevoreilly" - family = "Lumma" - last_modified = "2024-10-26" - sharing = "TLP:CLEAR" - yara_rule = open(os.path.join(os.path.dirname(__file__).split("/modules", 1)[0], f"data/yara/CAPE/{family}.yar")).read() - - def run(self, stream, matches): - return convert_to_MACO(extract_config(stream.read())) diff --git a/modules/processing/parsers/MACO/NanoCore.py b/modules/processing/parsers/MACO/NanoCore.py deleted file mode 100644 index 309f798de01..00000000000 --- a/modules/processing/parsers/MACO/NanoCore.py +++ /dev/null @@ -1,44 +0,0 @@ -from copy import deepcopy - -from maco.extractor import Extractor -from maco.model import ExtractorModel as MACOModel - -from modules.processing.parsers.CAPE.NanoCore import extract_config - - -def convert_to_MACO(raw_config: dict): - if not raw_config: - return None - - parsed_result = MACOModel(family="NanoCore", other=raw_config) - - config_copy = deepcopy(raw_config) - capabilities = {k: config_copy.pop(k) for k in list(config_copy.keys()) if config_copy[k] in ["True", "False"]} - - if "Version" in config_copy: - parsed_result.version = config_copy.pop("Version") - - if "Mutex" in config_copy: - parsed_result.mutex.append(config_copy.pop("Mutex")) - - for capability, enabled in capabilities.items(): - if enabled.lower() == "true": - parsed_result.capability_enabled.append(capability) - else: - parsed_result.capability_disabled.append(capability) - - for address in config_copy.pop("cncs", []): - host, port = address.split(":") - parsed_result.http.append(MACOModel.Http(hostname=host, port=port, usage="c2")) - - return parsed_result - - -class NanoCore(Extractor): - author = "kevoreilly" - family = "NanoCore" - last_modified = "2024-10-26" - sharing = "TLP:CLEAR" - - def run(self, stream, matches): - return convert_to_MACO(extract_config(stream.read())) diff --git a/modules/processing/parsers/MACO/Nighthawk.py b/modules/processing/parsers/MACO/Nighthawk.py deleted file mode 100644 index b1872886bed..00000000000 --- a/modules/processing/parsers/MACO/Nighthawk.py +++ /dev/null @@ -1,26 +0,0 @@ -import os - -from maco.extractor import Extractor -from maco.model import ExtractorModel as MACOModel - -from modules.processing.parsers.CAPE.Nighthawk import extract_config - - -def convert_to_MACO(raw_config: dict): - if not raw_config: - return None - - parsed_result = MACOModel(family="Nighthawk", other=raw_config) - - return parsed_result - - -class Nighthawk(Extractor): - author = "kevoreilly" - family = "Nighthawk" - last_modified = "2024-10-26" - sharing = "TLP:CLEAR" - yara_rule = open(os.path.join(os.path.dirname(__file__).split("/modules", 1)[0], f"data/yara/CAPE/{family}.yar")).read() - - def run(self, stream, matches): - return convert_to_MACO(extract_config(stream.read())) diff --git a/modules/processing/parsers/MACO/Njrat.py b/modules/processing/parsers/MACO/Njrat.py deleted file mode 100644 index f3f9b27de27..00000000000 --- a/modules/processing/parsers/MACO/Njrat.py +++ /dev/null @@ -1,33 +0,0 @@ -from maco.extractor import Extractor -from maco.model import ExtractorModel as MACOModel - -from modules.processing.parsers.CAPE.Njrat import extract_config - - -def convert_to_MACO(raw_config: dict): - if not raw_config: - return None - - parsed_result = MACOModel(family="Njrat", other=raw_config) - - if "version" in raw_config: - parsed_result.version = raw_config["version"] - - if "campaign_id" in raw_config: - parsed_result.campaign_id.append(raw_config["campaign_id"]) - - for c2 in raw_config.get("cncs", []): - host, port = c2.split(":") - parsed_result.http.append(MACOModel.Http(hostname=host, port=port, usage="c2")) - - return parsed_result - - -class Njrat(Extractor): - author = "kevoreilly" - family = "Njrat" - last_modified = "2024-10-26" - sharing = "TLP:CLEAR" - - def run(self, stream, matches): - return convert_to_MACO(extract_config(stream.read())) diff --git a/modules/processing/parsers/MACO/Oyster.py b/modules/processing/parsers/MACO/Oyster.py deleted file mode 100644 index 4a80f038cbf..00000000000 --- a/modules/processing/parsers/MACO/Oyster.py +++ /dev/null @@ -1,35 +0,0 @@ -import os - -from maco.extractor import Extractor -from maco.model import ExtractorModel as MACOModel - -from modules.processing.parsers.CAPE.Oyster import extract_config - - -def convert_to_MACO(raw_config: dict): - if not raw_config: - return None - - parsed_result = MACOModel(family="Oyster", other=raw_config) - - for address in raw_config.get("C2", []): - parsed_result.http.append(MACOModel.Http(uri=address, usage="c2")) - - if "Dll Version" in raw_config: - parsed_result.version = raw_config["Dll Version"] - - if "Strings" in raw_config: - parsed_result.decoded_strings = raw_config["Strings"] - - return parsed_result - - -class Oyster(Extractor): - author = "kevoreilly" - family = "Oyster" - last_modified = "2024-10-26" - sharing = "TLP:CLEAR" - yara_rule = open(os.path.join(os.path.dirname(__file__).split("/modules", 1)[0], f"data/yara/CAPE/{family}.yar")).read() - - def run(self, stream, matches): - return convert_to_MACO(extract_config(stream.read())) diff --git a/modules/processing/parsers/MACO/Pandora.py b/modules/processing/parsers/MACO/Pandora.py deleted file mode 100644 index b82bad0c02c..00000000000 --- a/modules/processing/parsers/MACO/Pandora.py +++ /dev/null @@ -1,50 +0,0 @@ -import os -from copy import deepcopy - -from maco.extractor import Extractor -from maco.model import ExtractorModel as MACOModel - -from modules.processing.parsers.CAPE.Pandora import extract_config - - -def convert_to_MACO(raw_config: dict): - if not raw_config: - return None - - config_copy = deepcopy(raw_config) - parsed_result = MACOModel( - family="Pandora", - mutex=[config_copy.pop("Mutex")], - campaign_id=[config_copy.pop("Campaign ID")], - version=config_copy.pop("Version"), - http=[dict(hostname=config_copy.pop("Domain"), port=config_copy.pop("Port"), password=config_copy.pop("Password"))], - other=raw_config, - ) - - parsed_result.paths.append( - MACOModel.Path(path=os.path.join(config_copy.pop("Install Path"), config_copy.pop("Install Name")), usage="install") - ) - - parsed_result.registry.append(MACOModel.Registry(key=config_copy.pop("HKCU Key"))) - parsed_result.registry.append(MACOModel.Registry(key=config_copy.pop("ActiveX Key"))) - - for field in list(config_copy.keys()): - # TODO: Unsure what's the value of the remaining fields - if config_copy[field].lower() in ["true", "false"]: - enabled = config_copy.pop(field).lower() == "true" - if enabled: - parsed_result.capability_enabled.append(field) - else: - parsed_result.capability_disabled.append(field) - - return parsed_result - - -class Pandora(Extractor): - author = "kevoreilly" - family = "Pandora" - last_modified = "2024-10-26" - sharing = "TLP:CLEAR" - - def run(self, stream, matches): - return convert_to_MACO(extract_config(stream.read())) diff --git a/modules/processing/parsers/MACO/PhemedroneStealer.py b/modules/processing/parsers/MACO/PhemedroneStealer.py deleted file mode 100644 index ef30b9032bf..00000000000 --- a/modules/processing/parsers/MACO/PhemedroneStealer.py +++ /dev/null @@ -1,23 +0,0 @@ -from maco.extractor import Extractor -from maco.model import ExtractorModel as MACOModel - -from modules.processing.parsers.CAPE.PhemedroneStealer import extract_config - - -def convert_to_MACO(raw_config: dict): - if not raw_config: - return None - - parsed_result = MACOModel(family="PhemedroneStealer", other=raw_config) - - return parsed_result - - -class PhemedroneStealer(Extractor): - author = "kevoreilly" - family = "PhemedroneStealer" - last_modified = "2024-10-26" - sharing = "TLP:CLEAR" - - def run(self, stream, matches): - return convert_to_MACO(extract_config(stream.read())) diff --git a/modules/processing/parsers/MACO/PikaBot.py b/modules/processing/parsers/MACO/PikaBot.py deleted file mode 100644 index 4409b7f6cab..00000000000 --- a/modules/processing/parsers/MACO/PikaBot.py +++ /dev/null @@ -1,35 +0,0 @@ -from maco.extractor import Extractor -from maco.model import ExtractorModel as MACOModel - -from modules.processing.parsers.CAPE.PikaBot import extract_config, rule_source - - -def convert_to_MACO(raw_config: dict): - if not raw_config: - return None - - parsed_result = MACOModel(family="PikaBot", other=raw_config) - - if "C2" in raw_config: - [parsed_result.http.append(MACOModel.Http(uri=c2, usage="c2")) for c2 in raw_config["C2"]] - parsed_result.binaries.append(MACOModel.Binary(datatype="payload", data=raw_config["Powershell"])) - elif "C2s" in raw_config: - parsed_result.version = raw_config["Version"] - parsed_result.campaign_id.append(raw_config["Campaign Name"]) - parsed_result.registry.append(MACOModel.Registry(key=raw_config["Registry Key"])) - for c2 in raw_config["C2s"]: - host, port = c2.split(":") - parsed_result.http.append(MACOModel.Http(hostname=host, port=port, user_agent=raw_config["User Agent"])) - - return parsed_result - - -class PikaBot(Extractor): - author = "kevoreilly" - family = "PikaBot" - last_modified = "2024-10-26" - sharing = "TLP:CLEAR" - yara_rule = rule_source - - def run(self, stream, matches): - return convert_to_MACO(extract_config(stream.read())) diff --git a/modules/processing/parsers/MACO/PlugX.py b/modules/processing/parsers/MACO/PlugX.py deleted file mode 100644 index c2ae83ea952..00000000000 --- a/modules/processing/parsers/MACO/PlugX.py +++ /dev/null @@ -1,23 +0,0 @@ -from maco.extractor import Extractor -from maco.model import ExtractorModel as MACOModel - -from modules.processing.parsers.CAPE.PlugX import extract_config - - -def convert_to_MACO(raw_config: dict): - if not raw_config: - return None - - parsed_result = MACOModel(family="PlugX", other=raw_config) - - return parsed_result - - -class PlugX(Extractor): - author = "kevoreilly" - family = "PlugX" - last_modified = "2024-10-26" - sharing = "TLP:CLEAR" - - def run(self, stream, matches): - return convert_to_MACO(extract_config(stream.read())) diff --git a/modules/processing/parsers/MACO/PoisonIvy.py b/modules/processing/parsers/MACO/PoisonIvy.py deleted file mode 100644 index e18175fa42d..00000000000 --- a/modules/processing/parsers/MACO/PoisonIvy.py +++ /dev/null @@ -1,45 +0,0 @@ -from maco.extractor import Extractor -from maco.model import ExtractorModel as MACOModel - -from modules.processing.parsers.CAPE.PoisonIvy import extract_config - - -def convert_to_MACO(raw_config: dict): - if not raw_config: - return None - - parsed_result = MACOModel(family="PoisonIvy", other=raw_config) - - if "Campaign ID" in raw_config: - parsed_result.campaign_id.append(raw_config["Campaign ID"]) - if "Group ID" in raw_config: - parsed_result.identifier.append(raw_config["Group ID"]) - if "Domains" in raw_config: - for domain_port in raw_config["Domains"].split("|"): - host, port = domain_port.split(":") - parsed_result.http.append(MACOModel.Http(hostname=host, port=port)) - if "Password" in raw_config: - parsed_result.password.append(raw_config["Password"]) - if "Mutex" in raw_config: - parsed_result.mutex.append(raw_config["Mutex"]) - - for field in list(raw_config.keys()): - value = raw_config[field] - if value.lower() == "true": - parsed_result.capability_enabled.append(field) - elif value.lower() == "false": - parsed_result.capability_disabled.append(field) - - return parsed_result - - -class PoisonIvy(Extractor): - author = "kevoreilly" - family = "PoisonIvy" - last_modified = "2024-10-26" - sharing = "TLP:CLEAR" - - def run(self, stream, matches): - output = extract_config(stream.read()) - if output: - return convert_to_MACO(output[0]) diff --git a/modules/processing/parsers/MACO/Punisher.py b/modules/processing/parsers/MACO/Punisher.py deleted file mode 100644 index 6bdfbb3c1be..00000000000 --- a/modules/processing/parsers/MACO/Punisher.py +++ /dev/null @@ -1,46 +0,0 @@ -import os -from copy import deepcopy - -from maco.extractor import Extractor -from maco.model import ExtractorModel as MACOModel - -from modules.processing.parsers.CAPE.Punisher import extract_config - - -def convert_to_MACO(raw_config: dict): - if not raw_config: - return None - - config_copy = deepcopy(raw_config) - parsed_result = MACOModel( - family="Punisher", - campaign_id=config_copy["Campaign Name"], - password=[config_copy["Password"]], - registry=[MACOModel.Registry(key=config_copy["Registry Key"])], - paths=[MACOModel.Path(path=os.path.join(config_copy["Install Path"], config_copy["Install Name"]))], - http=[MACOModel.Http(hostname=config_copy["Domain"], port=config_copy["Port"])], - other=raw_config, - ) - - for field in raw_config.keys(): - value = raw_config[field] - if value.lower() == "true": - parsed_result.capability_enabled.append(field) - elif value.lower() == "false": - parsed_result.capability_disabled.append(field) - else: - parsed_result.other[field] = value - - return parsed_result - - -class Punisher(Extractor): - author = "kevoreilly" - family = "Punisher" - last_modified = "2024-10-26" - sharing = "TLP:CLEAR" - - def run(self, stream, matches): - output = extract_config(stream.read()) - if output: - return convert_to_MACO(output[0]) diff --git a/modules/processing/parsers/MACO/QakBot.py b/modules/processing/parsers/MACO/QakBot.py deleted file mode 100644 index d8ee5c8c023..00000000000 --- a/modules/processing/parsers/MACO/QakBot.py +++ /dev/null @@ -1,28 +0,0 @@ -from maco.extractor import Extractor -from maco.model import ExtractorModel as MACOModel - -from modules.processing.parsers.CAPE.QakBot import extract_config, rule_source - - -def convert_to_MACO(raw_config: dict): - if not raw_config: - return None - - parsed_result = MACOModel(family="QakBot", other=raw_config) - - for address in raw_config.get("address", []) + raw_config.get("C2s", []): - host, port = address.split(":") - parsed_result.http.append(MACOModel.Http(hostname=host, port=port, usage="c2")) - - return parsed_result - - -class QakBot(Extractor): - author = "kevoreilly" - family = "QakBot" - last_modified = "2024-10-26" - sharing = "TLP:CLEAR" - yara_rule = rule_source - - def run(self, stream, matches): - return convert_to_MACO(extract_config(stream.read())) diff --git a/modules/processing/parsers/MACO/QuasarRAT.py b/modules/processing/parsers/MACO/QuasarRAT.py deleted file mode 100644 index e7a0aadf5e9..00000000000 --- a/modules/processing/parsers/MACO/QuasarRAT.py +++ /dev/null @@ -1,26 +0,0 @@ -import os - -from maco.extractor import Extractor -from maco.model import ExtractorModel as MACOModel - -from modules.processing.parsers.CAPE.QuasarRAT import extract_config - - -def convert_to_MACO(raw_config: dict): - if not raw_config: - return None - - parsed_result = MACOModel(family="QuasarRAT", other=raw_config) - - return parsed_result - - -class QuasarRAT(Extractor): - author = "kevoreilly" - family = "QuasarRAT" - last_modified = "2024-10-26" - sharing = "TLP:CLEAR" - yara_rule = open(os.path.join(os.path.dirname(__file__).split("/modules", 1)[0], f"data/yara/CAPE/{family}.yar")).read() - - def run(self, stream, matches): - return convert_to_MACO(extract_config(stream.read())) diff --git a/modules/processing/parsers/MACO/Quickbind.py b/modules/processing/parsers/MACO/Quickbind.py deleted file mode 100644 index 2a0b9101766..00000000000 --- a/modules/processing/parsers/MACO/Quickbind.py +++ /dev/null @@ -1,35 +0,0 @@ -import os - -from maco.extractor import Extractor -from maco.model import ExtractorModel as MACOModel - -from modules.processing.parsers.CAPE.Quickbind import extract_config - - -def convert_to_MACO(raw_config: dict): - if not raw_config: - return None - - parsed_result = MACOModel(family="Quickbind", other=raw_config) - - if "Mutex" in raw_config: - parsed_result.mutex = raw_config["Mutex"] - - for c2 in raw_config.get("C2", []): - parsed_result.http.append(MACOModel.Http(hostname=c2, usage="c2")) - - if "Encryption Key" in raw_config: - parsed_result.encryption.append(MACOModel.Encryption(key=raw_config["Encryption Key"])) - - return parsed_result - - -class Quickbind(Extractor): - author = "kevoreilly" - family = "Quickbind" - last_modified = "2024-10-26" - sharing = "TLP:CLEAR" - yara_rule = open(os.path.join(os.path.dirname(__file__).split("/modules", 1)[0], f"data/yara/CAPE/{family}.yar")).read() - - def run(self, stream, matches): - return convert_to_MACO(extract_config(stream.read())) diff --git a/modules/processing/parsers/MACO/RCSession.py b/modules/processing/parsers/MACO/RCSession.py deleted file mode 100644 index 3c79bc89e32..00000000000 --- a/modules/processing/parsers/MACO/RCSession.py +++ /dev/null @@ -1,44 +0,0 @@ -from maco.extractor import Extractor -from maco.model import ExtractorModel as MACOModel - -from modules.processing.parsers.CAPE.RCSession import extract_config, rule_source - - -def convert_to_MACO(raw_config: dict): - if not raw_config: - return None - - parsed_result = MACOModel(family="RCSession", other=raw_config) - - for address in raw_config.get("c2_address", []): - parsed_result.http.append(MACOModel.Http(hostname=address, usage="c2")) - - if "directory" in raw_config: - parsed_result.paths.append(MACOModel.Path(path=raw_config["directory"], usage="install")) - - service = {} - - if "servicename" in raw_config: - service["name"] = raw_config["servicename"] - if "servicedisplayname" in raw_config: - service["display_name"] = raw_config["servicedisplayname"] - if "servicedescription" in raw_config: - service["description"] = raw_config["servicedescription"] - if "filename" in raw_config: - service["dll"] = raw_config["filename"] - - if service: - parsed_result.service.append(MACOModel.Service(**service)) - - return parsed_result - - -class RCSession(Extractor): - author = "kevoreilly" - family = "RCSession" - last_modified = "2024-10-26" - sharing = "TLP:CLEAR" - yara_rule = rule_source - - def run(self, stream, matches): - return convert_to_MACO(extract_config(stream.read())) diff --git a/modules/processing/parsers/MACO/REvil.py b/modules/processing/parsers/MACO/REvil.py deleted file mode 100644 index f05f9196733..00000000000 --- a/modules/processing/parsers/MACO/REvil.py +++ /dev/null @@ -1,23 +0,0 @@ -from maco.extractor import Extractor -from maco.model import ExtractorModel as MACOModel - -from modules.processing.parsers.CAPE.REvil import extract_config - - -def convert_to_MACO(raw_config: dict): - if not raw_config: - return None - - parsed_result = MACOModel(family="REvil", other=raw_config) - - return parsed_result - - -class REvil(Extractor): - author = "kevoreilly" - family = "REvil" - last_modified = "2024-10-26" - sharing = "TLP:CLEAR" - - def run(self, stream, matches): - return convert_to_MACO(extract_config(stream.read())) diff --git a/modules/processing/parsers/MACO/RedLeaf.py b/modules/processing/parsers/MACO/RedLeaf.py deleted file mode 100644 index 22038c489ab..00000000000 --- a/modules/processing/parsers/MACO/RedLeaf.py +++ /dev/null @@ -1,36 +0,0 @@ -from maco.extractor import Extractor -from maco.model import ExtractorModel as MACOModel - -from modules.processing.parsers.CAPE.RedLeaf import extract_config, rule_source - - -def convert_to_MACO(raw_config: dict): - if not raw_config: - return None - - parsed_result = MACOModel(family="RedLeaf", other=raw_config) - - for address in raw_config.get("c2_address", []): - parsed_result.http.append(MACOModel.Http(hostname=address, usage="c2")) - - if "missionid" in raw_config: - parsed_result.campaign_id.append(raw_config["missionid"]) - - if "mutex" in raw_config: - parsed_result.mutex.append(raw_config["mutex"]) - - if "key" in raw_config: - parsed_result.other["key"] = raw_config["key"] - - return parsed_result - - -class RedLeaf(Extractor): - author = "kevoreilly" - family = "RedLeaf" - last_modified = "2024-10-26" - sharing = "TLP:CLEAR" - yara_rule = rule_source - - def run(self, stream, matches): - return convert_to_MACO(extract_config(stream.read())) diff --git a/modules/processing/parsers/MACO/RedLine.py b/modules/processing/parsers/MACO/RedLine.py deleted file mode 100644 index 3db57707287..00000000000 --- a/modules/processing/parsers/MACO/RedLine.py +++ /dev/null @@ -1,27 +0,0 @@ -from maco.extractor import Extractor -from maco.model import ExtractorModel as MACOModel - -from modules.processing.parsers.CAPE.RedLine import extract_config - - -def convert_to_MACO(raw_config: dict): - if not raw_config: - return None - - parsed_result = MACOModel(family="RedLine", other=raw_config) - - if "C2" in raw_config: - host, port = raw_config["C2"].split(":") - parsed_result.http.append(MACOModel.Http(hostname=host, port=port, usage="c2")) - - return parsed_result - - -class RedLine(Extractor): - author = "kevoreilly" - family = "RedLine" - last_modified = "2024-10-26" - sharing = "TLP:CLEAR" - - def run(self, stream, matches): - return convert_to_MACO(extract_config(stream.read())) diff --git a/modules/processing/parsers/MACO/Remcos.py b/modules/processing/parsers/MACO/Remcos.py deleted file mode 100644 index 739dd52b54f..00000000000 --- a/modules/processing/parsers/MACO/Remcos.py +++ /dev/null @@ -1,26 +0,0 @@ -import os - -from maco.extractor import Extractor -from maco.model import ExtractorModel as MACOModel - -from modules.processing.parsers.CAPE.Remcos import extract_config - - -def convert_to_MACO(raw_config: dict): - if not raw_config: - return None - - parsed_result = MACOModel(family="Remcos", other=raw_config) - - return parsed_result - - -class Remcos(Extractor): - author = "kevoreilly" - family = "Remcos" - last_modified = "2024-10-26" - sharing = "TLP:CLEAR" - yara_rule = open(os.path.join(os.path.dirname(__file__).split("/modules", 1)[0], f"data/yara/CAPE/{family}.yar")).read() - - def run(self, stream, matches): - return convert_to_MACO(extract_config(stream.read())) diff --git a/modules/processing/parsers/MACO/Retefe.py b/modules/processing/parsers/MACO/Retefe.py deleted file mode 100644 index 119d0af7c4c..00000000000 --- a/modules/processing/parsers/MACO/Retefe.py +++ /dev/null @@ -1,24 +0,0 @@ -from maco.extractor import Extractor -from maco.model import ExtractorModel as MACOModel - -from modules.processing.parsers.CAPE.Retefe import extract_config, rule_source - - -def convert_to_MACO(raw_config: dict): - if not raw_config: - return None - - parsed_result = MACOModel(family="Retefe", other=raw_config) - - return parsed_result - - -class Retefe(Extractor): - author = "kevoreilly" - family = "Retefe" - last_modified = "2024-10-26" - sharing = "TLP:CLEAR" - yara_rule = rule_source - - def run(self, stream, matches): - return convert_to_MACO(extract_config(stream.read())) diff --git a/modules/processing/parsers/MACO/Rhadamanthys.py b/modules/processing/parsers/MACO/Rhadamanthys.py deleted file mode 100644 index d98b140a08e..00000000000 --- a/modules/processing/parsers/MACO/Rhadamanthys.py +++ /dev/null @@ -1,27 +0,0 @@ -import os - -from maco.extractor import Extractor -from maco.model import ExtractorModel as MACOModel - -from modules.processing.parsers.CAPE.Rhadamanthys import extract_config - - -def convert_to_MACO(raw_config: dict): - if not raw_config: - return None - - parsed_result = MACOModel(family="Rhadamanthys", other=raw_config) - parsed_result.http = [MACOModel.Http(hostname=raw_config["C2"], usage="c2")] - - return parsed_result - - -class Rhadamanthys(Extractor): - author = "kevoreilly" - family = "Rhadamanthys" - last_modified = "2024-10-26" - sharing = "TLP:CLEAR" - yara_rule = open(os.path.join(os.path.dirname(__file__).split("/modules", 1)[0], f"data/yara/CAPE/{family}.yar")).read() - - def run(self, stream, matches): - return convert_to_MACO(extract_config(stream.read())) diff --git a/modules/processing/parsers/MACO/Rozena.py b/modules/processing/parsers/MACO/Rozena.py deleted file mode 100644 index ba019d79cd9..00000000000 --- a/modules/processing/parsers/MACO/Rozena.py +++ /dev/null @@ -1,27 +0,0 @@ -import os - -from maco.extractor import Extractor -from maco.model import ExtractorModel as MACOModel - -from modules.processing.parsers.CAPE.Rozena import extract_config - - -def convert_to_MACO(raw_config: dict): - if not raw_config: - return None - - parsed_result = MACOModel(family="Rozena", other=raw_config) - parsed_result.http = [MACOModel.Http(hostname=raw_config["C2"], port=raw_config["Port"], usage="c2")] - - return parsed_result - - -class Rozena(Extractor): - author = "kevoreilly" - family = "Rozena" - last_modified = "2024-10-26" - sharing = "TLP:CLEAR" - yara_rule = open(os.path.join(os.path.dirname(__file__).split("/modules", 1)[0], f"data/yara/CAPE/{family}.yar")).read() - - def run(self, stream, matches): - return convert_to_MACO(extract_config(stream.read())) diff --git a/modules/processing/parsers/MACO/SmallNet.py b/modules/processing/parsers/MACO/SmallNet.py deleted file mode 100644 index 5b81de3f3af..00000000000 --- a/modules/processing/parsers/MACO/SmallNet.py +++ /dev/null @@ -1,26 +0,0 @@ -from maco.extractor import Extractor -from maco.model import ExtractorModel as MACOModel - -from modules.processing.parsers.CAPE.SmallNet import extract_config - - -def convert_to_MACO(raw_config: dict): - if not raw_config: - return None - - parsed_result = MACOModel(family="SmallNet", other=raw_config) - - return parsed_result - - -class SmallNet(Extractor): - author = "kevoreilly" - family = "SmallNet" - last_modified = "2024-10-26" - sharing = "TLP:CLEAR" - - def run(self, stream, matches): - output = extract_config(stream.read()) - if output: - config = output if isinstance(output, dict) else output[0] - return convert_to_MACO(config) diff --git a/modules/processing/parsers/MACO/SmokeLoader.py b/modules/processing/parsers/MACO/SmokeLoader.py deleted file mode 100644 index ba61c9c08de..00000000000 --- a/modules/processing/parsers/MACO/SmokeLoader.py +++ /dev/null @@ -1,26 +0,0 @@ -from maco.extractor import Extractor -from maco.model import ExtractorModel as MACOModel - -from modules.processing.parsers.CAPE.SmokeLoader import extract_config, rule_source - - -def convert_to_MACO(raw_config: dict): - if not raw_config: - return None - - parsed_result = MACOModel( - family="SmokeLoader", other=raw_config, http=[MACOModel.Http(uri=c2, usage="c2") for c2 in raw_config["C2s"]] - ) - - return parsed_result - - -class SmokeLoader(Extractor): - author = "kevoreilly" - family = "SmokeLoader" - last_modified = "2024-10-26" - sharing = "TLP:CLEAR" - yara_rule = rule_source - - def run(self, stream, matches): - return convert_to_MACO(extract_config(stream.read())) diff --git a/modules/processing/parsers/MACO/Socks5Systemz.py b/modules/processing/parsers/MACO/Socks5Systemz.py deleted file mode 100644 index 9e6e2ab93a9..00000000000 --- a/modules/processing/parsers/MACO/Socks5Systemz.py +++ /dev/null @@ -1,31 +0,0 @@ -import os - -from maco.extractor import Extractor -from maco.model import ExtractorModel as MACOModel - -from modules.processing.parsers.CAPE.Socks5Systemz import extract_config - - -def convert_to_MACO(raw_config: dict): - if not raw_config: - return None - - parsed_result = MACOModel( - family="Socks5Systemz", - other=raw_config, - http=[MACOModel.Http(hostname=c2, usage="c2") for c2 in raw_config.get("C2s", [])] - + [MACOModel.Http(hostname=decoy, usage="decoy") for decoy in raw_config.get("Dummy domain", [])], - ) - - return parsed_result - - -class Socks5Systemz(Extractor): - author = "kevoreilly" - family = "Socks5Systemz" - last_modified = "2024-10-26" - sharing = "TLP:CLEAR" - yara_rule = open(os.path.join(os.path.dirname(__file__).split("/modules", 1)[0], f"data/yara/CAPE/{family}.yar")).read() - - def run(self, stream, matches): - return convert_to_MACO(extract_config(stream.read())) diff --git a/modules/processing/parsers/MACO/SparkRAT.py b/modules/processing/parsers/MACO/SparkRAT.py deleted file mode 100644 index deae637bd99..00000000000 --- a/modules/processing/parsers/MACO/SparkRAT.py +++ /dev/null @@ -1,34 +0,0 @@ -import os - -from maco.extractor import Extractor -from maco.model import ExtractorModel as MACOModel - -from modules.processing.parsers.CAPE.SparkRAT import extract_config - - -def convert_to_MACO(raw_config: dict): - if not raw_config: - return None - - parsed_result = MACOModel(family="SparkRAT", other=raw_config) - - url = f"http{'s' if raw_config['secure'] else ''}://{raw_config['host']}:{raw_config['port']}{raw_config['path']}" - - parsed_result.http.append( - MACOModel.Http(uri=url, hostname=raw_config["host"], port=raw_config["port"], path=raw_config["path"]) - ) - - parsed_result.identifier.append(raw_config["uuid"]) - - return parsed_result - - -class SparkRAT(Extractor): - author = "kevoreilly" - family = "SparkRAT" - last_modified = "2024-10-26" - sharing = "TLP:CLEAR" - yara_rule = open(os.path.join(os.path.dirname(__file__).split("/modules", 1)[0], f"data/yara/CAPE/{family}.yar")).read() - - def run(self, stream, matches): - return convert_to_MACO(extract_config(stream.read())) diff --git a/modules/processing/parsers/MACO/SquirrelWaffle.py b/modules/processing/parsers/MACO/SquirrelWaffle.py deleted file mode 100644 index 0790a7b6653..00000000000 --- a/modules/processing/parsers/MACO/SquirrelWaffle.py +++ /dev/null @@ -1,26 +0,0 @@ -from maco.extractor import Extractor -from maco.model import ExtractorModel as MACOModel - -from modules.processing.parsers.CAPE.SquirrelWaffle import extract_config, rule_source - - -def convert_to_MACO(raw_config: dict): - if not raw_config: - return None - - parsed_result = MACOModel( - family="SquirrelWaffle", other=raw_config, http=[MACOModel.Http(uri=c2, usage="c2") for c2 in raw_config["URLs"]] - ) - - return parsed_result - - -class SquirrelWaffle(Extractor): - author = "kevoreilly" - family = "SquirrelWaffle" - last_modified = "2024-10-26" - sharing = "TLP:CLEAR" - yara_rule = rule_source - - def run(self, stream, matches): - return convert_to_MACO(extract_config(stream.read())) diff --git a/modules/processing/parsers/MACO/Stealc.py b/modules/processing/parsers/MACO/Stealc.py deleted file mode 100644 index 9cd38a935b7..00000000000 --- a/modules/processing/parsers/MACO/Stealc.py +++ /dev/null @@ -1,26 +0,0 @@ -from maco.extractor import Extractor -from maco.model import ExtractorModel as MACOModel - -from modules.processing.parsers.CAPE.Stealc import RULE_SOURCE, extract_config - - -def convert_to_MACO(raw_config: dict): - if not raw_config: - return None - - parsed_result = MACOModel( - family="Stealc", other=raw_config, http=[MACOModel.Http(uri=c2, usage="c2") for c2 in raw_config["C2"]] - ) - - return parsed_result - - -class Stealc(Extractor): - author = "kevoreilly" - family = "Stealc" - last_modified = "2024-10-26" - sharing = "TLP:CLEAR" - yara_rule = RULE_SOURCE - - def run(self, stream, matches): - return convert_to_MACO(extract_config(stream.read())) diff --git a/modules/processing/parsers/MACO/Strrat.py b/modules/processing/parsers/MACO/Strrat.py deleted file mode 100644 index 58a5d5f93d9..00000000000 --- a/modules/processing/parsers/MACO/Strrat.py +++ /dev/null @@ -1,23 +0,0 @@ -from maco.extractor import Extractor -from maco.model import ExtractorModel as MACOModel - -from modules.processing.parsers.CAPE.Strrat import extract_config - - -def convert_to_MACO(raw_config: dict): - if not raw_config: - return None - - parsed_result = MACOModel(family="Strrat", other=raw_config) - - return parsed_result - - -class Strrat(Extractor): - author = "kevoreilly" - family = "Strrat" - last_modified = "2024-10-26" - sharing = "TLP:CLEAR" - - def run(self, stream, matches): - return convert_to_MACO(extract_config(stream.read())) diff --git a/modules/processing/parsers/MACO/TSCookie.py b/modules/processing/parsers/MACO/TSCookie.py deleted file mode 100644 index 7344c47e381..00000000000 --- a/modules/processing/parsers/MACO/TSCookie.py +++ /dev/null @@ -1,26 +0,0 @@ -import os - -from maco.extractor import Extractor -from maco.model import ExtractorModel as MACOModel - -from modules.processing.parsers.CAPE.TSCookie import extract_config - - -def convert_to_MACO(raw_config: dict): - if not raw_config: - return None - - parsed_result = MACOModel(family="TSCookie", other=raw_config) - - return parsed_result - - -class TSCookie(Extractor): - author = "kevoreilly" - family = "TSCookie" - last_modified = "2024-10-26" - sharing = "TLP:CLEAR" - yara_rule = open(os.path.join(os.path.dirname(__file__).split("/modules", 1)[0], f"data/yara/CAPE/{family}.yar")).read() - - def run(self, stream, matches): - return convert_to_MACO(extract_config(stream.read())) diff --git a/modules/processing/parsers/MACO/TrickBot.py b/modules/processing/parsers/MACO/TrickBot.py deleted file mode 100644 index 5962d7b46d7..00000000000 --- a/modules/processing/parsers/MACO/TrickBot.py +++ /dev/null @@ -1,24 +0,0 @@ -from maco.extractor import Extractor -from maco.model import ExtractorModel as MACOModel - -from modules.processing.parsers.CAPE.TrickBot import extract_config, rule_source - - -def convert_to_MACO(raw_config: dict): - if not raw_config: - return None - - parsed_result = MACOModel(family="TrickBot", other=raw_config) - - return parsed_result - - -class TrickBot(Extractor): - author = "kevoreilly" - family = "TrickBot" - last_modified = "2024-10-26" - sharing = "TLP:CLEAR" - yara_rule = rule_source - - def run(self, stream, matches): - return convert_to_MACO(extract_config(stream.read())) diff --git a/modules/processing/parsers/MACO/UrsnifV3.py b/modules/processing/parsers/MACO/UrsnifV3.py deleted file mode 100644 index 2e8caefbdb0..00000000000 --- a/modules/processing/parsers/MACO/UrsnifV3.py +++ /dev/null @@ -1,26 +0,0 @@ -import os - -from maco.extractor import Extractor -from maco.model import ExtractorModel as MACOModel - -from modules.processing.parsers.CAPE.UrsnifV3 import extract_config - - -def convert_to_MACO(raw_config: dict): - if not raw_config: - return None - - parsed_result = MACOModel(family="UrsnifV3", other=raw_config) - - return parsed_result - - -class UrsnifV3(Extractor): - author = "kevoreilly" - family = "UrsnifV3" - last_modified = "2024-10-26" - sharing = "TLP:CLEAR" - yara_rule = open(os.path.join(os.path.dirname(__file__).split("/modules", 1)[0], f"data/yara/CAPE/{family}.yar")).read() - - def run(self, stream, matches): - return convert_to_MACO(extract_config(stream.read())) diff --git a/modules/processing/parsers/MACO/VenomRat.py b/modules/processing/parsers/MACO/VenomRat.py deleted file mode 100644 index de2f70ddd85..00000000000 --- a/modules/processing/parsers/MACO/VenomRat.py +++ /dev/null @@ -1,23 +0,0 @@ -from maco.extractor import Extractor -from maco.model import ExtractorModel as MACOModel - -from modules.processing.parsers.CAPE.VenomRAT import extract_config - - -def convert_to_MACO(raw_config: dict): - if not raw_config: - return None - - parsed_result = MACOModel(family="VenomRAT", other=raw_config) - - return parsed_result - - -class VenomRAT(Extractor): - author = "kevoreilly" - family = "VenomRAT" - last_modified = "2024-10-26" - sharing = "TLP:CLEAR" - - def run(self, stream, matches): - return convert_to_MACO(extract_config(stream.read())) diff --git a/modules/processing/parsers/MACO/WarzoneRAT.py b/modules/processing/parsers/MACO/WarzoneRAT.py deleted file mode 100644 index 186ed365448..00000000000 --- a/modules/processing/parsers/MACO/WarzoneRAT.py +++ /dev/null @@ -1,27 +0,0 @@ -from maco.extractor import Extractor -from maco.model import ExtractorModel as MACOModel - -from modules.processing.parsers.CAPE.WarzoneRAT import extract_config - - -def convert_to_MACO(raw_config: dict): - if not raw_config: - return None - - parsed_result = MACOModel(family="WarzoneRAT", other=raw_config) - - if "C2" in raw_config: - host, port = raw_config["C2"].split(":") - parsed_result.http.append(MACOModel.Http(hostname=host, port=port, usage="c2")) - - return parsed_result - - -class WarzoneRAT(Extractor): - author = "kevoreilly" - family = "WarzoneRAT" - last_modified = "2024-10-26" - sharing = "TLP:CLEAR" - - def run(self, stream, matches): - return convert_to_MACO(extract_config(stream.read())) diff --git a/modules/processing/parsers/MACO/XWorm.py b/modules/processing/parsers/MACO/XWorm.py deleted file mode 100644 index 8d81f728c21..00000000000 --- a/modules/processing/parsers/MACO/XWorm.py +++ /dev/null @@ -1,26 +0,0 @@ -import os - -from maco.extractor import Extractor -from maco.model import ExtractorModel as MACOModel - -from modules.processing.parsers.CAPE.XWorm import extract_config - - -def convert_to_MACO(raw_config: dict): - if not raw_config: - return None - - parsed_result = MACOModel(family="XWorm", other=raw_config) - - return parsed_result - - -class XWorm(Extractor): - author = "kevoreilly" - family = "XWorm" - last_modified = "2024-10-26" - sharing = "TLP:CLEAR" - yara_rule = open(os.path.join(os.path.dirname(__file__).split("/modules", 1)[0], f"data/yara/CAPE/{family}.yar")).read() - - def run(self, stream, matches): - return convert_to_MACO(extract_config(stream.read())) diff --git a/modules/processing/parsers/MACO/XenoRAT.py b/modules/processing/parsers/MACO/XenoRAT.py deleted file mode 100644 index 31fc541f702..00000000000 --- a/modules/processing/parsers/MACO/XenoRAT.py +++ /dev/null @@ -1,26 +0,0 @@ -import os - -from maco.extractor import Extractor -from maco.model import ExtractorModel as MACOModel - -from modules.processing.parsers.CAPE.XenoRAT import extract_config - - -def convert_to_MACO(raw_config: dict): - if not raw_config: - return None - - parsed_result = MACOModel(family="XenoRAT", other=raw_config) - - return parsed_result - - -class XenoRAT(Extractor): - author = "kevoreilly" - family = "XenoRAT" - last_modified = "2024-10-26" - sharing = "TLP:CLEAR" - yara_rule = open(os.path.join(os.path.dirname(__file__).split("/modules", 1)[0], f"data/yara/CAPE/{family}.yar")).read() - - def run(self, stream, matches): - return convert_to_MACO(extract_config(stream.read())) diff --git a/modules/processing/parsers/MACO/Zloader.py b/modules/processing/parsers/MACO/Zloader.py deleted file mode 100644 index a6e085f4ce0..00000000000 --- a/modules/processing/parsers/MACO/Zloader.py +++ /dev/null @@ -1,33 +0,0 @@ -from maco.extractor import Extractor -from maco.model import ExtractorModel as MACOModel - -from modules.processing.parsers.CAPE.Zloader import extract_config, rule_source - - -def convert_to_MACO(raw_config: dict): - if not raw_config: - return None - - parsed_result = MACOModel(family="Zloader", other=raw_config) - - if "Campaign ID" in raw_config: - parsed_result.campaign_id = [raw_config["Campaign ID"]] - - if "RC4 key" in raw_config: - parsed_result.encryption = [MACOModel.Encryption(algorithm="RC4", key=raw_config[:"RC4 key"])] - - for address in raw_config.get("address", []): - parsed_result.http.append(MACOModel.Http(uri=address)) - - return parsed_result - - -class Zloader(Extractor): - author = "kevoreilly" - family = "Zloader" - last_modified = "2024-10-26" - sharing = "TLP:CLEAR" - yara_rule = rule_source - - def run(self, stream, matches): - return convert_to_MACO(extract_config(stream.read())) diff --git a/modules/processing/parsers/MACO/__init__.py b/modules/processing/parsers/MACO/__init__.py deleted file mode 100644 index f39e5e8d683..00000000000 --- a/modules/processing/parsers/MACO/__init__.py +++ /dev/null @@ -1 +0,0 @@ -# Init diff --git a/modules/processing/parsers/MACO/test_maco.py b/modules/processing/parsers/MACO/test_maco.py deleted file mode 100644 index d502c95b81c..00000000000 --- a/modules/processing/parsers/MACO/test_maco.py +++ /dev/null @@ -1,10 +0,0 @@ -from maco.extractor import Extractor - - -class Test(Extractor): - author = "test" - family = "test" - last_modified = "2024-10-20" - - def run(self, stream, matches): - pass diff --git a/modules/processing/parsers/RATDecoders/__init__.py b/modules/processing/parsers/RATDecoders/__init__.py deleted file mode 100644 index f39e5e8d683..00000000000 --- a/modules/processing/parsers/RATDecoders/__init__.py +++ /dev/null @@ -1 +0,0 @@ -# Init diff --git a/modules/processing/parsers/RATDecoders/test_rats.py b/modules/processing/parsers/RATDecoders/test_rats.py deleted file mode 100644 index c75b0e1eacf..00000000000 --- a/modules/processing/parsers/RATDecoders/test_rats.py +++ /dev/null @@ -1,13 +0,0 @@ -from malwareconfig.common import Decoder - -# https://youtu.be/C_ijc7A5oAc?list=OLAK5uy_kGTSX7lmPmKwIVzgFLqd0x3dSF6HQhE-I - - -class TEST_RATS(Decoder): - decoder_name = "TestRats" - decoder__version = 1 - decoder_author = "doomedraven" - decoder_description = "Test module to ensure that framework loads properly." - - def __init__(self): - pass diff --git a/modules/processing/parsers/__init__.py b/modules/processing/parsers/__init__.py deleted file mode 100644 index f39e5e8d683..00000000000 --- a/modules/processing/parsers/__init__.py +++ /dev/null @@ -1 +0,0 @@ -# Init diff --git a/modules/processing/parsers/malduck/LICENSE b/modules/processing/parsers/malduck/LICENSE deleted file mode 100644 index f288702d2fa..00000000000 --- a/modules/processing/parsers/malduck/LICENSE +++ /dev/null @@ -1,674 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 - - Copyright (C) 2007 Free Software Foundation, Inc. - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The GNU General Public License is a free, copyleft license for -software and other kinds of works. - - The licenses for most software and other practical works are designed -to take away your freedom to share and change the works. By contrast, -the GNU General Public License is intended to guarantee your freedom to -share and change all versions of a program--to make sure it remains free -software for all its users. We, the Free Software Foundation, use the -GNU General Public License for most of our software; it applies also to -any other work released this way by its authors. You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -them if you wish), that you receive source code or can get it if you -want it, that you can change the software or use pieces of it in new -free programs, and that you know you can do these things. - - To protect your rights, we need to prevent others from denying you -these rights or asking you to surrender the rights. Therefore, you have -certain responsibilities if you distribute copies of the software, or if -you modify it: responsibilities to respect the freedom of others. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must pass on to the recipients the same -freedoms that you received. You must make sure that they, too, receive -or can get the source code. And you must show them these terms so they -know their rights. - - Developers that use the GNU GPL protect your rights with two steps: -(1) assert copyright on the software, and (2) offer you this License -giving you legal permission to copy, distribute and/or modify it. - - For the developers' and authors' protection, the GPL clearly explains -that there is no warranty for this free software. For both users' and -authors' sake, the GPL requires that modified versions be marked as -changed, so that their problems will not be attributed erroneously to -authors of previous versions. - - Some devices are designed to deny users access to install or run -modified versions of the software inside them, although the manufacturer -can do so. This is fundamentally incompatible with the aim of -protecting users' freedom to change the software. The systematic -pattern of such abuse occurs in the area of products for individuals to -use, which is precisely where it is most unacceptable. Therefore, we -have designed this version of the GPL to prohibit the practice for those -products. If such problems arise substantially in other domains, we -stand ready to extend this provision to those domains in future versions -of the GPL, as needed to protect the freedom of users. - - Finally, every program is threatened constantly by software patents. -States should not allow patents to restrict development and use of -software on general-purpose computers, but in those that do, we wish to -avoid the special danger that patents applied to a free program could -make it effectively proprietary. To prevent this, the GPL assures that -patents cannot be used to render the program non-free. - - The precise terms and conditions for copying, distribution and -modification follow. - - TERMS AND CONDITIONS - - 0. Definitions. - - "This License" refers to version 3 of the GNU General Public License. - - "Copyright" also means copyright-like laws that apply to other kinds of -works, such as semiconductor masks. - - "The Program" refers to any copyrightable work licensed under this -License. Each licensee is addressed as "you". "Licensees" and -"recipients" may be individuals or organizations. - - To "modify" a work means to copy from or adapt all or part of the work -in a fashion requiring copyright permission, other than the making of an -exact copy. The resulting work is called a "modified version" of the -earlier work or a work "based on" the earlier work. - - A "covered work" means either the unmodified Program or a work based -on the Program. - - To "propagate" a work means to do anything with it that, without -permission, would make you directly or secondarily liable for -infringement under applicable copyright law, except executing it on a -computer or modifying a private copy. Propagation includes copying, -distribution (with or without modification), making available to the -public, and in some countries other activities as well. - - To "convey" a work means any kind of propagation that enables other -parties to make or receive copies. Mere interaction with a user through -a computer network, with no transfer of a copy, is not conveying. - - An interactive user interface displays "Appropriate Legal Notices" -to the extent that it includes a convenient and prominently visible -feature that (1) displays an appropriate copyright notice, and (2) -tells the user that there is no warranty for the work (except to the -extent that warranties are provided), that licensees may convey the -work under this License, and how to view a copy of this License. If -the interface presents a list of user commands or options, such as a -menu, a prominent item in the list meets this criterion. - - 1. Source Code. - - The "source code" for a work means the preferred form of the work -for making modifications to it. "Object code" means any non-source -form of a work. - - A "Standard Interface" means an interface that either is an official -standard defined by a recognized standards body, or, in the case of -interfaces specified for a particular programming language, one that -is widely used among developers working in that language. - - The "System Libraries" of an executable work include anything, other -than the work as a whole, that (a) is included in the normal form of -packaging a Major Component, but which is not part of that Major -Component, and (b) serves only to enable use of the work with that -Major Component, or to implement a Standard Interface for which an -implementation is available to the public in source code form. A -"Major Component", in this context, means a major essential component -(kernel, window system, and so on) of the specific operating system -(if any) on which the executable work runs, or a compiler used to -produce the work, or an object code interpreter used to run it. - - The "Corresponding Source" for a work in object code form means all -the source code needed to generate, install, and (for an executable -work) run the object code and to modify the work, including scripts to -control those activities. However, it does not include the work's -System Libraries, or general-purpose tools or generally available free -programs which are used unmodified in performing those activities but -which are not part of the work. For example, Corresponding Source -includes interface definition files associated with source files for -the work, and the source code for shared libraries and dynamically -linked subprograms that the work is specifically designed to require, -such as by intimate data communication or control flow between those -subprograms and other parts of the work. - - The Corresponding Source need not include anything that users -can regenerate automatically from other parts of the Corresponding -Source. - - The Corresponding Source for a work in source code form is that -same work. - - 2. Basic Permissions. - - All rights granted under this License are granted for the term of -copyright on the Program, and are irrevocable provided the stated -conditions are met. This License explicitly affirms your unlimited -permission to run the unmodified Program. The output from running a -covered work is covered by this License only if the output, given its -content, constitutes a covered work. This License acknowledges your -rights of fair use or other equivalent, as provided by copyright law. - - You may make, run and propagate covered works that you do not -convey, without conditions so long as your license otherwise remains -in force. You may convey covered works to others for the sole purpose -of having them make modifications exclusively for you, or provide you -with facilities for running those works, provided that you comply with -the terms of this License in conveying all material for which you do -not control copyright. Those thus making or running the covered works -for you must do so exclusively on your behalf, under your direction -and control, on terms that prohibit them from making any copies of -your copyrighted material outside their relationship with you. - - Conveying under any other circumstances is permitted solely under -the conditions stated below. Sublicensing is not allowed; section 10 -makes it unnecessary. - - 3. Protecting Users' Legal Rights From Anti-Circumvention Law. - - No covered work shall be deemed part of an effective technological -measure under any applicable law fulfilling obligations under article -11 of the WIPO copyright treaty adopted on 20 December 1996, or -similar laws prohibiting or restricting circumvention of such -measures. - - When you convey a covered work, you waive any legal power to forbid -circumvention of technological measures to the extent such circumvention -is effected by exercising rights under this License with respect to -the covered work, and you disclaim any intention to limit operation or -modification of the work as a means of enforcing, against the work's -users, your or third parties' legal rights to forbid circumvention of -technological measures. - - 4. Conveying Verbatim Copies. - - You may convey verbatim copies of the Program's source code as you -receive it, in any medium, provided that you conspicuously and -appropriately publish on each copy an appropriate copyright notice; -keep intact all notices stating that this License and any -non-permissive terms added in accord with section 7 apply to the code; -keep intact all notices of the absence of any warranty; and give all -recipients a copy of this License along with the Program. - - You may charge any price or no price for each copy that you convey, -and you may offer support or warranty protection for a fee. - - 5. Conveying Modified Source Versions. - - You may convey a work based on the Program, or the modifications to -produce it from the Program, in the form of source code under the -terms of section 4, provided that you also meet all of these conditions: - - a) The work must carry prominent notices stating that you modified - it, and giving a relevant date. - - b) The work must carry prominent notices stating that it is - released under this License and any conditions added under section - 7. This requirement modifies the requirement in section 4 to - "keep intact all notices". - - c) You must license the entire work, as a whole, under this - License to anyone who comes into possession of a copy. This - License will therefore apply, along with any applicable section 7 - additional terms, to the whole of the work, and all its parts, - regardless of how they are packaged. This License gives no - permission to license the work in any other way, but it does not - invalidate such permission if you have separately received it. - - d) If the work has interactive user interfaces, each must display - Appropriate Legal Notices; however, if the Program has interactive - interfaces that do not display Appropriate Legal Notices, your - work need not make them do so. - - A compilation of a covered work with other separate and independent -works, which are not by their nature extensions of the covered work, -and which are not combined with it such as to form a larger program, -in or on a volume of a storage or distribution medium, is called an -"aggregate" if the compilation and its resulting copyright are not -used to limit the access or legal rights of the compilation's users -beyond what the individual works permit. Inclusion of a covered work -in an aggregate does not cause this License to apply to the other -parts of the aggregate. - - 6. Conveying Non-Source Forms. - - You may convey a covered work in object code form under the terms -of sections 4 and 5, provided that you also convey the -machine-readable Corresponding Source under the terms of this License, -in one of these ways: - - a) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by the - Corresponding Source fixed on a durable physical medium - customarily used for software interchange. - - b) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by a - written offer, valid for at least three years and valid for as - long as you offer spare parts or customer support for that product - model, to give anyone who possesses the object code either (1) a - copy of the Corresponding Source for all the software in the - product that is covered by this License, on a durable physical - medium customarily used for software interchange, for a price no - more than your reasonable cost of physically performing this - conveying of source, or (2) access to copy the - Corresponding Source from a network server at no charge. - - c) Convey individual copies of the object code with a copy of the - written offer to provide the Corresponding Source. This - alternative is allowed only occasionally and noncommercially, and - only if you received the object code with such an offer, in accord - with subsection 6b. - - d) Convey the object code by offering access from a designated - place (gratis or for a charge), and offer equivalent access to the - Corresponding Source in the same way through the same place at no - further charge. You need not require recipients to copy the - Corresponding Source along with the object code. If the place to - copy the object code is a network server, the Corresponding Source - may be on a different server (operated by you or a third party) - that supports equivalent copying facilities, provided you maintain - clear directions next to the object code saying where to find the - Corresponding Source. Regardless of what server hosts the - Corresponding Source, you remain obligated to ensure that it is - available for as long as needed to satisfy these requirements. - - e) Convey the object code using peer-to-peer transmission, provided - you inform other peers where the object code and Corresponding - Source of the work are being offered to the general public at no - charge under subsection 6d. - - A separable portion of the object code, whose source code is excluded -from the Corresponding Source as a System Library, need not be -included in conveying the object code work. - - A "User Product" is either (1) a "consumer product", which means any -tangible personal property which is normally used for personal, family, -or household purposes, or (2) anything designed or sold for incorporation -into a dwelling. In determining whether a product is a consumer product, -doubtful cases shall be resolved in favor of coverage. For a particular -product received by a particular user, "normally used" refers to a -typical or common use of that class of product, regardless of the status -of the particular user or of the way in which the particular user -actually uses, or expects or is expected to use, the product. A product -is a consumer product regardless of whether the product has substantial -commercial, industrial or non-consumer uses, unless such uses represent -the only significant mode of use of the product. - - "Installation Information" for a User Product means any methods, -procedures, authorization keys, or other information required to install -and execute modified versions of a covered work in that User Product from -a modified version of its Corresponding Source. The information must -suffice to ensure that the continued functioning of the modified object -code is in no case prevented or interfered with solely because -modification has been made. - - If you convey an object code work under this section in, or with, or -specifically for use in, a User Product, and the conveying occurs as -part of a transaction in which the right of possession and use of the -User Product is transferred to the recipient in perpetuity or for a -fixed term (regardless of how the transaction is characterized), the -Corresponding Source conveyed under this section must be accompanied -by the Installation Information. But this requirement does not apply -if neither you nor any third party retains the ability to install -modified object code on the User Product (for example, the work has -been installed in ROM). - - The requirement to provide Installation Information does not include a -requirement to continue to provide support service, warranty, or updates -for a work that has been modified or installed by the recipient, or for -the User Product in which it has been modified or installed. Access to a -network may be denied when the modification itself materially and -adversely affects the operation of the network or violates the rules and -protocols for communication across the network. - - Corresponding Source conveyed, and Installation Information provided, -in accord with this section must be in a format that is publicly -documented (and with an implementation available to the public in -source code form), and must require no special password or key for -unpacking, reading or copying. - - 7. Additional Terms. - - "Additional permissions" are terms that supplement the terms of this -License by making exceptions from one or more of its conditions. -Additional permissions that are applicable to the entire Program shall -be treated as though they were included in this License, to the extent -that they are valid under applicable law. If additional permissions -apply only to part of the Program, that part may be used separately -under those permissions, but the entire Program remains governed by -this License without regard to the additional permissions. - - When you convey a copy of a covered work, you may at your option -remove any additional permissions from that copy, or from any part of -it. (Additional permissions may be written to require their own -removal in certain cases when you modify the work.) You may place -additional permissions on material, added by you to a covered work, -for which you have or can give appropriate copyright permission. - - Notwithstanding any other provision of this License, for material you -add to a covered work, you may (if authorized by the copyright holders of -that material) supplement the terms of this License with terms: - - a) Disclaiming warranty or limiting liability differently from the - terms of sections 15 and 16 of this License; or - - b) Requiring preservation of specified reasonable legal notices or - author attributions in that material or in the Appropriate Legal - Notices displayed by works containing it; or - - c) Prohibiting misrepresentation of the origin of that material, or - requiring that modified versions of such material be marked in - reasonable ways as different from the original version; or - - d) Limiting the use for publicity purposes of names of licensors or - authors of the material; or - - e) Declining to grant rights under trademark law for use of some - trade names, trademarks, or service marks; or - - f) Requiring indemnification of licensors and authors of that - material by anyone who conveys the material (or modified versions of - it) with contractual assumptions of liability to the recipient, for - any liability that these contractual assumptions directly impose on - those licensors and authors. - - All other non-permissive additional terms are considered "further -restrictions" within the meaning of section 10. If the Program as you -received it, or any part of it, contains a notice stating that it is -governed by this License along with a term that is a further -restriction, you may remove that term. If a license document contains -a further restriction but permits relicensing or conveying under this -License, you may add to a covered work material governed by the terms -of that license document, provided that the further restriction does -not survive such relicensing or conveying. - - If you add terms to a covered work in accord with this section, you -must place, in the relevant source files, a statement of the -additional terms that apply to those files, or a notice indicating -where to find the applicable terms. - - Additional terms, permissive or non-permissive, may be stated in the -form of a separately written license, or stated as exceptions; -the above requirements apply either way. - - 8. Termination. - - You may not propagate or modify a covered work except as expressly -provided under this License. Any attempt otherwise to propagate or -modify it is void, and will automatically terminate your rights under -this License (including any patent licenses granted under the third -paragraph of section 11). - - However, if you cease all violation of this License, then your -license from a particular copyright holder is reinstated (a) -provisionally, unless and until the copyright holder explicitly and -finally terminates your license, and (b) permanently, if the copyright -holder fails to notify you of the violation by some reasonable means -prior to 60 days after the cessation. - - Moreover, your license from a particular copyright holder is -reinstated permanently if the copyright holder notifies you of the -violation by some reasonable means, this is the first time you have -received notice of violation of this License (for any work) from that -copyright holder, and you cure the violation prior to 30 days after -your receipt of the notice. - - Termination of your rights under this section does not terminate the -licenses of parties who have received copies or rights from you under -this License. If your rights have been terminated and not permanently -reinstated, you do not qualify to receive new licenses for the same -material under section 10. - - 9. Acceptance Not Required for Having Copies. - - You are not required to accept this License in order to receive or -run a copy of the Program. Ancillary propagation of a covered work -occurring solely as a consequence of using peer-to-peer transmission -to receive a copy likewise does not require acceptance. However, -nothing other than this License grants you permission to propagate or -modify any covered work. These actions infringe copyright if you do -not accept this License. Therefore, by modifying or propagating a -covered work, you indicate your acceptance of this License to do so. - - 10. Automatic Licensing of Downstream Recipients. - - Each time you convey a covered work, the recipient automatically -receives a license from the original licensors, to run, modify and -propagate that work, subject to this License. You are not responsible -for enforcing compliance by third parties with this License. - - An "entity transaction" is a transaction transferring control of an -organization, or substantially all assets of one, or subdividing an -organization, or merging organizations. If propagation of a covered -work results from an entity transaction, each party to that -transaction who receives a copy of the work also receives whatever -licenses to the work the party's predecessor in interest had or could -give under the previous paragraph, plus a right to possession of the -Corresponding Source of the work from the predecessor in interest, if -the predecessor has it or can get it with reasonable efforts. - - You may not impose any further restrictions on the exercise of the -rights granted or affirmed under this License. For example, you may -not impose a license fee, royalty, or other charge for exercise of -rights granted under this License, and you may not initiate litigation -(including a cross-claim or counterclaim in a lawsuit) alleging that -any patent claim is infringed by making, using, selling, offering for -sale, or importing the Program or any portion of it. - - 11. Patents. - - A "contributor" is a copyright holder who authorizes use under this -License of the Program or a work on which the Program is based. The -work thus licensed is called the contributor's "contributor version". - - A contributor's "essential patent claims" are all patent claims -owned or controlled by the contributor, whether already acquired or -hereafter acquired, that would be infringed by some manner, permitted -by this License, of making, using, or selling its contributor version, -but do not include claims that would be infringed only as a -consequence of further modification of the contributor version. For -purposes of this definition, "control" includes the right to grant -patent sublicenses in a manner consistent with the requirements of -this License. - - Each contributor grants you a non-exclusive, worldwide, royalty-free -patent license under the contributor's essential patent claims, to -make, use, sell, offer for sale, import and otherwise run, modify and -propagate the contents of its contributor version. - - In the following three paragraphs, a "patent license" is any express -agreement or commitment, however denominated, not to enforce a patent -(such as an express permission to practice a patent or covenant not to -sue for patent infringement). To "grant" such a patent license to a -party means to make such an agreement or commitment not to enforce a -patent against the party. - - If you convey a covered work, knowingly relying on a patent license, -and the Corresponding Source of the work is not available for anyone -to copy, free of charge and under the terms of this License, through a -publicly available network server or other readily accessible means, -then you must either (1) cause the Corresponding Source to be so -available, or (2) arrange to deprive yourself of the benefit of the -patent license for this particular work, or (3) arrange, in a manner -consistent with the requirements of this License, to extend the patent -license to downstream recipients. "Knowingly relying" means you have -actual knowledge that, but for the patent license, your conveying the -covered work in a country, or your recipient's use of the covered work -in a country, would infringe one or more identifiable patents in that -country that you have reason to believe are valid. - - If, pursuant to or in connection with a single transaction or -arrangement, you convey, or propagate by procuring conveyance of, a -covered work, and grant a patent license to some of the parties -receiving the covered work authorizing them to use, propagate, modify -or convey a specific copy of the covered work, then the patent license -you grant is automatically extended to all recipients of the covered -work and works based on it. - - A patent license is "discriminatory" if it does not include within -the scope of its coverage, prohibits the exercise of, or is -conditioned on the non-exercise of one or more of the rights that are -specifically granted under this License. You may not convey a covered -work if you are a party to an arrangement with a third party that is -in the business of distributing software, under which you make payment -to the third party based on the extent of your activity of conveying -the work, and under which the third party grants, to any of the -parties who would receive the covered work from you, a discriminatory -patent license (a) in connection with copies of the covered work -conveyed by you (or copies made from those copies), or (b) primarily -for and in connection with specific products or compilations that -contain the covered work, unless you entered into that arrangement, -or that patent license was granted, prior to 28 March 2007. - - Nothing in this License shall be construed as excluding or limiting -any implied license or other defenses to infringement that may -otherwise be available to you under applicable patent law. - - 12. No Surrender of Others' Freedom. - - If conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot convey a -covered work so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you may -not convey it at all. For example, if you agree to terms that obligate you -to collect a royalty for further conveying from those to whom you convey -the Program, the only way you could satisfy both those terms and this -License would be to refrain entirely from conveying the Program. - - 13. Use with the GNU Affero General Public License. - - Notwithstanding any other provision of this License, you have -permission to link or combine any covered work with a work licensed -under version 3 of the GNU Affero General Public License into a single -combined work, and to convey the resulting work. The terms of this -License will continue to apply to the part which is the covered work, -but the special requirements of the GNU Affero General Public License, -section 13, concerning interaction through a network will apply to the -combination as such. - - 14. Revised Versions of this License. - - The Free Software Foundation may publish revised and/or new versions of -the GNU General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - - Each version is given a distinguishing version number. If the -Program specifies that a certain numbered version of the GNU General -Public License "or any later version" applies to it, you have the -option of following the terms and conditions either of that numbered -version or of any later version published by the Free Software -Foundation. If the Program does not specify a version number of the -GNU General Public License, you may choose any version ever published -by the Free Software Foundation. - - If the Program specifies that a proxy can decide which future -versions of the GNU General Public License can be used, that proxy's -public statement of acceptance of a version permanently authorizes you -to choose that version for the Program. - - Later license versions may give you additional or different -permissions. However, no additional obligations are imposed on any -author or copyright holder as a result of your choosing to follow a -later version. - - 15. Disclaimer of Warranty. - - THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY -APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT -HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY -OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, -THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM -IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF -ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. Limitation of Liability. - - IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS -THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY -GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE -USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF -DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD -PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), -EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF -SUCH DAMAGES. - - 17. Interpretation of Sections 15 and 16. - - If the disclaimer of warranty and limitation of liability provided -above cannot be given local legal effect according to their terms, -reviewing courts shall apply local law that most closely approximates -an absolute waiver of all civil liability in connection with the -Program, unless a warranty or assumption of liability accompanies a -copy of the Program in return for a fee. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -state the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - -Also add information on how to contact you by electronic and paper mail. - - If the program does terminal interaction, make it output a short -notice like this when it starts in an interactive mode: - - Copyright (C) - This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, your program's commands -might be different; for a GUI interface, you would use an "about box". - - You should also get your employer (if you work as a programmer) or school, -if any, to sign a "copyright disclaimer" for the program, if necessary. -For more information on this, and how to apply and follow the GNU GPL, see -. - - The GNU General Public License does not permit incorporating your program -into proprietary programs. If your program is a subroutine library, you -may consider it more useful to permit linking proprietary applications with -the library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. But first, please read -. diff --git a/modules/processing/parsers/malduck/README.md b/modules/processing/parsers/malduck/README.md deleted file mode 100644 index 8abda618019..00000000000 --- a/modules/processing/parsers/malduck/README.md +++ /dev/null @@ -1,29 +0,0 @@ -:duck: Malduck -========= - -Malduck is your ducky companion in malware analysis journeys. It is mostly based on [Roach](https://github.com/hatching/roach) project, which derives many concepts from [mlib](https://github.com/mak/mlib) -library created by [Maciej Kotowicz](https://lokalhost.pl). The purpose of fork was to make Roach independent from [Cuckoo Sandbox](https://cuckoosandbox.org/) project, but still supporting its internal `procmem` format. - -Malduck provides many improvements resulting from CERT.pl codebase, making scripts written for malware analysis purposes much shorter and more powerful. - -Improvements -============ - -* Support for (non)memory-mapped PE images without header fix-up. -* Searching for wildcarded byte sequences -* Support for x64 disassembly -* Fixed-precision integer types -* Many improvements in ProcessMemory - -Usage -========== - -Installing may be performed by running - -``` -pip install malduck -``` - -Usage documentation can be found [on readthedocs](https://malduck.readthedocs.io/en/latest/). - -![Co-financed by the Connecting Europe Facility by of the European Union](https://www.cert.pl/wp-content/uploads/2019/02/en_horizontal_cef_logo-1.png) diff --git a/modules/processing/parsers/malduck/__init__.py b/modules/processing/parsers/malduck/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/modules/processing/parsers/malduck/test_malduck.py b/modules/processing/parsers/malduck/test_malduck.py deleted file mode 100644 index 7d19b9a4bab..00000000000 --- a/modules/processing/parsers/malduck/test_malduck.py +++ /dev/null @@ -1,15 +0,0 @@ -from malduck.extractor import Extractor - -__author__ = "doomedraven" -__version__ = "1.0.0" - - -class TEST_MALDUCK(Extractor): - """ - TEST Configuration Extractor - """ - - family = "TEST_MALDUCK" - - def TEST_MALDUCK(self): - pass diff --git a/modules/processing/parsers/mwcp/SmokeLoader.py b/modules/processing/parsers/mwcp/SmokeLoader.py deleted file mode 100644 index 72543ddddec..00000000000 --- a/modules/processing/parsers/mwcp/SmokeLoader.py +++ /dev/null @@ -1,165 +0,0 @@ -# Copyright (C) 2018 Kevin O'Reilly (kevin.oreilly@contextis.co.uk) -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU 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 General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import struct - -import pefile -import yara -from mwcp.parser import Parser - -rule_source = """ -rule SmokeLoader -{ - meta: - author = "kev" - description = "SmokeLoader C2 decryption function" - cape_type = "SmokeLoader Payload" - strings: - $decrypt64_1 = {44 0F B6 CF 48 8B D0 49 03 D9 4C 2B D8 8B 4B 01 41 8A 04 13 41 BA 04 00 00 00 0F C9 32 C1 C1 F9 08 49 FF CA 75 F6 F6 D0 88 02 48 FF C2 49 FF C9 75 DB 49 8B C0 48 8B 5C 24 30 48 83 C4 20 5F C3} - $decrypt64_2 = {40 84 FF 90 90 E8 00 00 00 00 5E 48 83 C6 1C 49 8B F8 A4 80 3E 00 75 FA 80 07 00 48 8B 5C 24 30 48 83 C4 20 5F C3} - $decrypt32_1 = {03 EE 8B D7 2B C7 8B F8 8B 4D 01 8A 04 17 6A 04 0F C9 5B 32 C1 C1 F9 08 4B 75 F8 F6 D0 88 02 42 4E 75 E5 8B 7C 24 14 8B C7 5F 5E 5D 5B 59 59 C3} - $ref64_1 = {40 53 48 83 EC 20 8B 05 ?? ?? ?? ?? 83 F8 ?? 75 27 33 C0 89 05 ?? ?? ?? ?? 84 C9 74 1B BB E8 03 00 00 B9 58 02 00 00 FF 15 ?? ?? ?? ?? 48 FF CB 75 F0 8B 05 ?? ?? ?? ?? 48 63 C8 48 8D 05} - $ref64_2 = {8B 05 ?? ?? ?? ?? 33 C9 83 F8 04 0F 44 C1 48 63 C8 89 05 ?? ?? ?? ?? 48 8D 05 ?? ?? ?? ?? 48 8B 0C C8 E9} - $ref32_1 = {8A C1 8B 0D 70 6D 00 10 83 F9 02 75 27 33 C9 89 0D 70 6D 00 10 84 C0 74 1B 56 BE E8 03 00 00 68 58 02 00 00 FF 15 38 6E 00 10 4E 75 F2 8B 0D 70 6D 00 10 5E 8B 0C 8D} - condition: - (any of ($decrypt*)) and (any of ($ref*)) -} -""" - - -def yara_scan(raw_data, rule_name): - addresses = {} - yara_rules = yara.compile(source=rule_source) - matches = yara_rules.match(data=raw_data) - for match in matches: - if match.rule == "SmokeLoader": - for item in match.strings: - if item[1] == rule_name: - addresses[item[1]] = item[0] - return addresses - - -def xor_decode(buffer, key): - byte_key = 0xFF - for i in range(0, 4): - byte_key = byte_key ^ (key >> (i * 8) & 0xFF) - return "".join(chr(ord(x) ^ byte_key) for x in buffer) - - -class SmokeLoader(Parser): - - DESCRIPTION = "SmokeLoader configuration parser." - AUTHOR = "kevoreilly" - - def run(self): - filebuf = self.file_object.file_data - - try: - pe = pefile.PE(data=filebuf, fast_load=False) - image_base = pe.OPTIONAL_HEADER.ImageBase - except Exception: - image_base = 0 - - table_ref = yara_scan(filebuf, "$ref64_1") - if table_ref: - table_ref_offset = int(table_ref["$ref64_1"]) - table_delta = struct.unpack("i", filebuf[table_ref_offset + 62 : table_ref_offset + 66])[0] - table_offset = table_ref_offset + table_delta + 66 - - table_loop = True - while table_loop: - c2_offset = 0 - if image_base: - c2_rva = struct.unpack("Q", filebuf[table_offset : table_offset + 8])[0] - if not c2_rva: - table_loop = False - else: - c2_rva -= image_base - if c2_rva and c2_rva < 0x8000: - c2_offset = pe.get_offset_from_rva(c2_rva) - else: - table_loop = False - else: - c2_offset = struct.unpack("I", filebuf[table_offset : table_offset + 4])[0] & 0xFFFF - if c2_offset and c2_offset < 0x8000: - try: - c2_size = struct.unpack("B", filebuf[c2_offset : c2_offset + 1])[0] - c2_key = struct.unpack("I", filebuf[c2_offset + c2_size + 1 : c2_offset + c2_size + 5])[0] - c2_url = xor_decode(filebuf[c2_offset + 1 : c2_offset + c2_size + 1], c2_key).decode("ascii") - if c2_url: - self.reporter.add_metadata("address", c2_url) - except Exception: - table_loop = False - else: - table_loop = False - table_offset += 8 - return - else: - table_ref = yara_scan(filebuf, "$ref64_2") - if table_ref: - table_ref_offset = int(table_ref["$ref64_2"]) - table_delta = struct.unpack("i", filebuf[table_ref_offset + 26 : table_ref_offset + 30])[0] - table_offset = table_ref_offset + table_delta + 30 - - for index in range(0, 2): - if image_base: - c2_rva = struct.unpack("Q", filebuf[table_offset : table_offset + 8])[0] - image_base - c2_offset = pe.get_offset_from_rva(c2_rva) - else: - c2_offset = struct.unpack("I", filebuf[table_offset : table_offset + 4])[0] & 0xFFFF - c2_size = struct.unpack("B", filebuf[c2_offset : c2_offset + 1])[0] - c2_key = struct.unpack("I", filebuf[c2_offset + c2_size + 1 : c2_offset + c2_size + 5])[0] - try: - c2_url = xor_decode(filebuf[c2_offset + 1 : c2_offset + c2_size + 1], c2_key).decode("ascii") - if c2_url: - self.reporter.add_metadata("address", c2_url) - except Exception: - pass - table_offset += 8 - return - else: - table_ref = yara_scan(filebuf, "$ref32_1") - if table_ref: - table_ref_offset = int(table_ref["$ref32_1"]) - table_rva = struct.unpack("i", filebuf[table_ref_offset + 55 : table_ref_offset + 59])[0] - image_base - table_offset = pe.get_offset_from_rva(table_rva) - - table_loop = True - while table_loop: - c2_offset = 0 - if image_base: - c2_rva = struct.unpack("I", filebuf[table_offset : table_offset + 4])[0] - if not c2_rva: - table_loop = False - else: - c2_rva -= image_base - if c2_rva and c2_rva < 0x8000: - c2_offset = pe.get_offset_from_rva(c2_rva) - else: - table_loop = False - else: - c2_offset = struct.unpack("I", filebuf[table_offset : table_offset + 4])[0] & 0xFFFF - if c2_offset and c2_offset < 0x8000: - try: - c2_size = struct.unpack("B", filebuf[c2_offset : c2_offset + 1])[0] - c2_key = struct.unpack("I", filebuf[c2_offset + c2_size + 1 : c2_offset + c2_size + 5])[0] - c2_url = xor_decode(filebuf[c2_offset + 1 : c2_offset + c2_size + 1], c2_key).decode("ascii") - if c2_url: - self.reporter.add_metadata("address", c2_url) - except Exception: - table_loop = False - else: - table_loop = False - table_offset += 4 - return diff --git a/modules/processing/parsers/mwcp/__init__.py b/modules/processing/parsers/mwcp/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/modules/processing/parsers/mwcp/test_mwcp.py b/modules/processing/parsers/mwcp/test_mwcp.py deleted file mode 100644 index 6a64efb6c3c..00000000000 --- a/modules/processing/parsers/mwcp/test_mwcp.py +++ /dev/null @@ -1,9 +0,0 @@ -from mwcp.parser import Parser - - -class MWCP_TEST(Parser): - DESCRIPTION = "Test module to ensure that framework loads properly." - AUTHOR = "doomedraven" - - def run(self): - pass diff --git a/poetry.lock b/poetry.lock index 26063d23dd1..2c4b225cef7 100644 --- a/poetry.lock +++ b/poetry.lock @@ -31,13 +31,13 @@ files = [ [[package]] name = "anyio" -version = "4.6.0" +version = "4.6.2.post1" description = "High level compatibility layer for multiple asynchronous event loop implementations" optional = false python-versions = ">=3.9" files = [ - {file = "anyio-4.6.0-py3-none-any.whl", hash = "sha256:c7d2e9d63e31599eeb636c8c5c03a7e108d73b345f064f1c19fdc87b79036a9a"}, - {file = "anyio-4.6.0.tar.gz", hash = "sha256:137b4559cbb034c477165047febb6ff83f390fc3b20bf181c1fc0a728cb8beeb"}, + {file = "anyio-4.6.2.post1-py3-none-any.whl", hash = "sha256:6d170c36fba3bdd840c73d3868c1e777e33676a69c3a72cf0a0d5d6d8009b61d"}, + {file = "anyio-4.6.2.post1.tar.gz", hash = "sha256:4c8bc31ccdb51c7f7bd251f51c609e038d63e34219b44aa86e47576389880b4c"}, ] [package.dependencies] @@ -48,7 +48,7 @@ typing-extensions = {version = ">=4.1", markers = "python_version < \"3.11\""} [package.extras] doc = ["Sphinx (>=7.4,<8.0)", "packaging", "sphinx-autodoc-typehints (>=1.2.0)", "sphinx-rtd-theme"] -test = ["anyio[trio]", "coverage[toml] (>=7)", "exceptiongroup (>=1.2.0)", "hypothesis (>=4.0)", "psutil (>=5.9)", "pytest (>=7.0)", "pytest-mock (>=3.6.1)", "trustme", "uvloop (>=0.21.0b1)"] +test = ["anyio[trio]", "coverage[toml] (>=7)", "exceptiongroup (>=1.2.0)", "hypothesis (>=4.0)", "psutil (>=5.9)", "pytest (>=7.0)", "pytest-mock (>=3.6.1)", "trustme", "truststore (>=0.9.1)", "uvloop (>=0.21.0b1)"] trio = ["trio (>=0.26.1)"] [[package]] @@ -193,33 +193,33 @@ lxml = ["lxml"] [[package]] name = "black" -version = "24.8.0" +version = "24.10.0" description = "The uncompromising code formatter." optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "black-24.8.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:09cdeb74d494ec023ded657f7092ba518e8cf78fa8386155e4a03fdcc44679e6"}, - {file = "black-24.8.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:81c6742da39f33b08e791da38410f32e27d632260e599df7245cccee2064afeb"}, - {file = "black-24.8.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:707a1ca89221bc8a1a64fb5e15ef39cd755633daa672a9db7498d1c19de66a42"}, - {file = "black-24.8.0-cp310-cp310-win_amd64.whl", hash = "sha256:d6417535d99c37cee4091a2f24eb2b6d5ec42b144d50f1f2e436d9fe1916fe1a"}, - {file = "black-24.8.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:fb6e2c0b86bbd43dee042e48059c9ad7830abd5c94b0bc518c0eeec57c3eddc1"}, - {file = "black-24.8.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:837fd281f1908d0076844bc2b801ad2d369c78c45cf800cad7b61686051041af"}, - {file = "black-24.8.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:62e8730977f0b77998029da7971fa896ceefa2c4c4933fcd593fa599ecbf97a4"}, - {file = "black-24.8.0-cp311-cp311-win_amd64.whl", hash = "sha256:72901b4913cbac8972ad911dc4098d5753704d1f3c56e44ae8dce99eecb0e3af"}, - {file = "black-24.8.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:7c046c1d1eeb7aea9335da62472481d3bbf3fd986e093cffd35f4385c94ae368"}, - {file = "black-24.8.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:649f6d84ccbae73ab767e206772cc2d7a393a001070a4c814a546afd0d423aed"}, - {file = "black-24.8.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2b59b250fdba5f9a9cd9d0ece6e6d993d91ce877d121d161e4698af3eb9c1018"}, - {file = "black-24.8.0-cp312-cp312-win_amd64.whl", hash = "sha256:6e55d30d44bed36593c3163b9bc63bf58b3b30e4611e4d88a0c3c239930ed5b2"}, - {file = "black-24.8.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:505289f17ceda596658ae81b61ebbe2d9b25aa78067035184ed0a9d855d18afd"}, - {file = "black-24.8.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:b19c9ad992c7883ad84c9b22aaa73562a16b819c1d8db7a1a1a49fb7ec13c7d2"}, - {file = "black-24.8.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1f13f7f386f86f8121d76599114bb8c17b69d962137fc70efe56137727c7047e"}, - {file = "black-24.8.0-cp38-cp38-win_amd64.whl", hash = "sha256:f490dbd59680d809ca31efdae20e634f3fae27fba3ce0ba3208333b713bc3920"}, - {file = "black-24.8.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:eab4dd44ce80dea27dc69db40dab62d4ca96112f87996bca68cd75639aeb2e4c"}, - {file = "black-24.8.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:3c4285573d4897a7610054af5a890bde7c65cb466040c5f0c8b732812d7f0e5e"}, - {file = "black-24.8.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9e84e33b37be070ba135176c123ae52a51f82306def9f7d063ee302ecab2cf47"}, - {file = "black-24.8.0-cp39-cp39-win_amd64.whl", hash = "sha256:73bbf84ed136e45d451a260c6b73ed674652f90a2b3211d6a35e78054563a9bb"}, - {file = "black-24.8.0-py3-none-any.whl", hash = "sha256:972085c618ee94f402da1af548a4f218c754ea7e5dc70acb168bfaca4c2542ed"}, - {file = "black-24.8.0.tar.gz", hash = "sha256:2500945420b6784c38b9ee885af039f5e7471ef284ab03fa35ecdde4688cd83f"}, + {file = "black-24.10.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e6668650ea4b685440857138e5fe40cde4d652633b1bdffc62933d0db4ed9812"}, + {file = "black-24.10.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:1c536fcf674217e87b8cc3657b81809d3c085d7bf3ef262ead700da345bfa6ea"}, + {file = "black-24.10.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:649fff99a20bd06c6f727d2a27f401331dc0cc861fb69cde910fe95b01b5928f"}, + {file = "black-24.10.0-cp310-cp310-win_amd64.whl", hash = "sha256:fe4d6476887de70546212c99ac9bd803d90b42fc4767f058a0baa895013fbb3e"}, + {file = "black-24.10.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5a2221696a8224e335c28816a9d331a6c2ae15a2ee34ec857dcf3e45dbfa99ad"}, + {file = "black-24.10.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f9da3333530dbcecc1be13e69c250ed8dfa67f43c4005fb537bb426e19200d50"}, + {file = "black-24.10.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4007b1393d902b48b36958a216c20c4482f601569d19ed1df294a496eb366392"}, + {file = "black-24.10.0-cp311-cp311-win_amd64.whl", hash = "sha256:394d4ddc64782e51153eadcaaca95144ac4c35e27ef9b0a42e121ae7e57a9175"}, + {file = "black-24.10.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:b5e39e0fae001df40f95bd8cc36b9165c5e2ea88900167bddf258bacef9bbdc3"}, + {file = "black-24.10.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:d37d422772111794b26757c5b55a3eade028aa3fde43121ab7b673d050949d65"}, + {file = "black-24.10.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:14b3502784f09ce2443830e3133dacf2c0110d45191ed470ecb04d0f5f6fcb0f"}, + {file = "black-24.10.0-cp312-cp312-win_amd64.whl", hash = "sha256:30d2c30dc5139211dda799758559d1b049f7f14c580c409d6ad925b74a4208a8"}, + {file = "black-24.10.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:1cbacacb19e922a1d75ef2b6ccaefcd6e93a2c05ede32f06a21386a04cedb981"}, + {file = "black-24.10.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:1f93102e0c5bb3907451063e08b9876dbeac810e7da5a8bfb7aeb5a9ef89066b"}, + {file = "black-24.10.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ddacb691cdcdf77b96f549cf9591701d8db36b2f19519373d60d31746068dbf2"}, + {file = "black-24.10.0-cp313-cp313-win_amd64.whl", hash = "sha256:680359d932801c76d2e9c9068d05c6b107f2584b2a5b88831c83962eb9984c1b"}, + {file = "black-24.10.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:17374989640fbca88b6a448129cd1745c5eb8d9547b464f281b251dd00155ccd"}, + {file = "black-24.10.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:63f626344343083322233f175aaf372d326de8436f5928c042639a4afbbf1d3f"}, + {file = "black-24.10.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ccfa1d0cb6200857f1923b602f978386a3a2758a65b52e0950299ea014be6800"}, + {file = "black-24.10.0-cp39-cp39-win_amd64.whl", hash = "sha256:2cd9c95431d94adc56600710f8813ee27eea544dd118d45896bb734e9d7a0dc7"}, + {file = "black-24.10.0-py3-none-any.whl", hash = "sha256:3bb2b7a1f7b685f85b11fed1ef10f8a9148bceb49853e47a294a3dd963c1dd7d"}, + {file = "black-24.10.0.tar.gz", hash = "sha256:846ea64c97afe3bc677b761787993be4991810ecc7a4a937816dd6bddedc4875"}, ] [package.dependencies] @@ -233,7 +233,7 @@ typing-extensions = {version = ">=4.0.1", markers = "python_version < \"3.11\""} [package.extras] colorama = ["colorama (>=0.4.3)"] -d = ["aiohttp (>=3.7.4)", "aiohttp (>=3.7.4,!=3.9.0)"] +d = ["aiohttp (>=3.10)"] jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"] uvloop = ["uvloop (>=0.15.2)"] @@ -261,6 +261,32 @@ files = [ {file = "cachetools-5.5.0.tar.gz", hash = "sha256:2cc24fb4cbe39633fb7badd9db9ca6295d766d9c2995f245725a46715d050f2a"}, ] +[[package]] +name = "cape-parsers" +version = "0.1.4" +description = "CAPE: Malware Configuration Extraction" +optional = false +python-versions = "<4.0,>=3.10" +files = [ + {file = "cape_parsers-0.1.4-py3-none-any.whl", hash = "sha256:4957cfd4c4215c550a27ca8d3dd87a60dd834fc6b7785cf0785d35ce04211e72"}, + {file = "cape_parsers-0.1.4.tar.gz", hash = "sha256:00a0541d9947257cacb6485ab513dee46812a90c22883bcc8c5eef592ff8750f"}, +] + +[package.dependencies] +capstone = ">=4.0.2" +dncil = ">=1.0.2" +dnfile = ">=0.15.1" +netstruct = "1.1.2" +pefile = "*" +pycryptodomex = ">=3.20.0" +rat-king-parser = ">=3.1.3" +regex = ">=2024.9.11" +unicorn = "2.1.1" +yara-python = "4.5.1" + +[package.extras] +maco = ["maco (==1.1.8)"] + [[package]] name = "capstone" version = "4.0.2" @@ -290,13 +316,13 @@ pycryptodome = "*" [[package]] name = "certifi" -version = "2024.7.4" +version = "2024.8.30" description = "Python package for providing Mozilla's CA Bundle." optional = false python-versions = ">=3.6" files = [ - {file = "certifi-2024.7.4-py3-none-any.whl", hash = "sha256:c198e21b1289c2ab85ee4e67bb4b4ef3ead0892059901a8d5b622f24a1101e90"}, - {file = "certifi-2024.7.4.tar.gz", hash = "sha256:5a1e7645bc0ec61a09e26c36f6106dd4cf40c6db3a1fb6352b0244e7fb057c7b"}, + {file = "certifi-2024.8.30-py3-none-any.whl", hash = "sha256:922820b53db7a7257ffbda3f597266d435245903d80737e34f8a45ff3e3230d8"}, + {file = "certifi-2024.8.30.tar.gz", hash = "sha256:bec941d2aa8195e248a60b31ff9f0558284cf01a52591ceda73ea9afffd69fd9"}, ] [[package]] @@ -421,101 +447,116 @@ files = [ [[package]] name = "charset-normalizer" -version = "3.3.2" +version = "3.4.0" description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." optional = false python-versions = ">=3.7.0" files = [ - {file = "charset-normalizer-3.3.2.tar.gz", hash = "sha256:f30c3cb33b24454a82faecaf01b19c18562b1e89558fb6c56de4d9118a032fd5"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:25baf083bf6f6b341f4121c2f3c548875ee6f5339300e08be3f2b2ba1721cdd3"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:06435b539f889b1f6f4ac1758871aae42dc3a8c0e24ac9e60c2384973ad73027"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9063e24fdb1e498ab71cb7419e24622516c4a04476b17a2dab57e8baa30d6e03"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6897af51655e3691ff853668779c7bad41579facacf5fd7253b0133308cf000d"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1d3193f4a680c64b4b6a9115943538edb896edc190f0b222e73761716519268e"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cd70574b12bb8a4d2aaa0094515df2463cb429d8536cfb6c7ce983246983e5a6"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8465322196c8b4d7ab6d1e049e4c5cb460d0394da4a27d23cc242fbf0034b6b5"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a9a8e9031d613fd2009c182b69c7b2c1ef8239a0efb1df3f7c8da66d5dd3d537"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:beb58fe5cdb101e3a055192ac291b7a21e3b7ef4f67fa1d74e331a7f2124341c"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:e06ed3eb3218bc64786f7db41917d4e686cc4856944f53d5bdf83a6884432e12"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:2e81c7b9c8979ce92ed306c249d46894776a909505d8f5a4ba55b14206e3222f"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:572c3763a264ba47b3cf708a44ce965d98555f618ca42c926a9c1616d8f34269"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fd1abc0d89e30cc4e02e4064dc67fcc51bd941eb395c502aac3ec19fab46b519"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-win32.whl", hash = "sha256:3d47fa203a7bd9c5b6cee4736ee84ca03b8ef23193c0d1ca99b5089f72645c73"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:10955842570876604d404661fbccbc9c7e684caf432c09c715ec38fbae45ae09"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:802fe99cca7457642125a8a88a084cef28ff0cf9407060f7b93dca5aa25480db"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:573f6eac48f4769d667c4442081b1794f52919e7edada77495aaed9236d13a96"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:549a3a73da901d5bc3ce8d24e0600d1fa85524c10287f6004fbab87672bf3e1e"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f27273b60488abe721a075bcca6d7f3964f9f6f067c8c4c605743023d7d3944f"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ceae2f17a9c33cb48e3263960dc5fc8005351ee19db217e9b1bb15d28c02574"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:65f6f63034100ead094b8744b3b97965785388f308a64cf8d7c34f2f2e5be0c4"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:753f10e867343b4511128c6ed8c82f7bec3bd026875576dfd88483c5c73b2fd8"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4a78b2b446bd7c934f5dcedc588903fb2f5eec172f3d29e52a9096a43722adfc"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e537484df0d8f426ce2afb2d0f8e1c3d0b114b83f8850e5f2fbea0e797bd82ae"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:eb6904c354526e758fda7167b33005998fb68c46fbc10e013ca97f21ca5c8887"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:deb6be0ac38ece9ba87dea880e438f25ca3eddfac8b002a2ec3d9183a454e8ae"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:4ab2fe47fae9e0f9dee8c04187ce5d09f48eabe611be8259444906793ab7cbce"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:80402cd6ee291dcb72644d6eac93785fe2c8b9cb30893c1af5b8fdd753b9d40f"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-win32.whl", hash = "sha256:7cd13a2e3ddeed6913a65e66e94b51d80a041145a026c27e6bb76c31a853c6ab"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-win_amd64.whl", hash = "sha256:663946639d296df6a2bb2aa51b60a2454ca1cb29835324c640dafb5ff2131a77"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:0b2b64d2bb6d3fb9112bafa732def486049e63de9618b5843bcdd081d8144cd8"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:ddbb2551d7e0102e7252db79ba445cdab71b26640817ab1e3e3648dad515003b"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:55086ee1064215781fff39a1af09518bc9255b50d6333f2e4c74ca09fac6a8f6"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8f4a014bc36d3c57402e2977dada34f9c12300af536839dc38c0beab8878f38a"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a10af20b82360ab00827f916a6058451b723b4e65030c5a18577c8b2de5b3389"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8d756e44e94489e49571086ef83b2bb8ce311e730092d2c34ca8f7d925cb20aa"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:90d558489962fd4918143277a773316e56c72da56ec7aa3dc3dbbe20fdfed15b"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6ac7ffc7ad6d040517be39eb591cac5ff87416c2537df6ba3cba3bae290c0fed"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:7ed9e526742851e8d5cc9e6cf41427dfc6068d4f5a3bb03659444b4cabf6bc26"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:8bdb58ff7ba23002a4c5808d608e4e6c687175724f54a5dade5fa8c67b604e4d"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:6b3251890fff30ee142c44144871185dbe13b11bab478a88887a639655be1068"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:b4a23f61ce87adf89be746c8a8974fe1c823c891d8f86eb218bb957c924bb143"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:efcb3f6676480691518c177e3b465bcddf57cea040302f9f4e6e191af91174d4"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-win32.whl", hash = "sha256:d965bba47ddeec8cd560687584e88cf699fd28f192ceb452d1d7ee807c5597b7"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-win_amd64.whl", hash = "sha256:96b02a3dc4381e5494fad39be677abcb5e6634bf7b4fa83a6dd3112607547001"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:95f2a5796329323b8f0512e09dbb7a1860c46a39da62ecb2324f116fa8fdc85c"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c002b4ffc0be611f0d9da932eb0f704fe2602a9a949d1f738e4c34c75b0863d5"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a981a536974bbc7a512cf44ed14938cf01030a99e9b3a06dd59578882f06f985"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3287761bc4ee9e33561a7e058c72ac0938c4f57fe49a09eae428fd88aafe7bb6"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:42cb296636fcc8b0644486d15c12376cb9fa75443e00fb25de0b8602e64c1714"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0a55554a2fa0d408816b3b5cedf0045f4b8e1a6065aec45849de2d6f3f8e9786"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:c083af607d2515612056a31f0a8d9e0fcb5876b7bfc0abad3ecd275bc4ebc2d5"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:87d1351268731db79e0f8e745d92493ee2841c974128ef629dc518b937d9194c"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:bd8f7df7d12c2db9fab40bdd87a7c09b1530128315d047a086fa3ae3435cb3a8"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:c180f51afb394e165eafe4ac2936a14bee3eb10debc9d9e4db8958fe36afe711"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:8c622a5fe39a48f78944a87d4fb8a53ee07344641b0562c540d840748571b811"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-win32.whl", hash = "sha256:db364eca23f876da6f9e16c9da0df51aa4f104a972735574842618b8c6d999d4"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-win_amd64.whl", hash = "sha256:86216b5cee4b06df986d214f664305142d9c76df9b6512be2738aa72a2048f99"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:6463effa3186ea09411d50efc7d85360b38d5f09b870c48e4600f63af490e56a"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6c4caeef8fa63d06bd437cd4bdcf3ffefe6738fb1b25951440d80dc7df8c03ac"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:37e55c8e51c236f95b033f6fb391d7d7970ba5fe7ff453dad675e88cf303377a"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fb69256e180cb6c8a894fee62b3afebae785babc1ee98b81cdf68bbca1987f33"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ae5f4161f18c61806f411a13b0310bea87f987c7d2ecdbdaad0e94eb2e404238"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b2b0a0c0517616b6869869f8c581d4eb2dd83a4d79e0ebcb7d373ef9956aeb0a"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:45485e01ff4d3630ec0d9617310448a8702f70e9c01906b0d0118bdf9d124cf2"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:eb00ed941194665c332bf8e078baf037d6c35d7c4f3102ea2d4f16ca94a26dc8"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:2127566c664442652f024c837091890cb1942c30937add288223dc895793f898"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:a50aebfa173e157099939b17f18600f72f84eed3049e743b68ad15bd69b6bf99"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:4d0d1650369165a14e14e1e47b372cfcb31d6ab44e6e33cb2d4e57265290044d"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:923c0c831b7cfcb071580d3f46c4baf50f174be571576556269530f4bbd79d04"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:06a81e93cd441c56a9b65d8e1d043daeb97a3d0856d177d5c90ba85acb3db087"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-win32.whl", hash = "sha256:6ef1d82a3af9d3eecdba2321dc1b3c238245d890843e040e41e470ffa64c3e25"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-win_amd64.whl", hash = "sha256:eb8821e09e916165e160797a6c17edda0679379a4be5c716c260e836e122f54b"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:c235ebd9baae02f1b77bcea61bce332cb4331dc3617d254df3323aa01ab47bd4"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5b4c145409bef602a690e7cfad0a15a55c13320ff7a3ad7ca59c13bb8ba4d45d"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:68d1f8a9e9e37c1223b656399be5d6b448dea850bed7d0f87a8311f1ff3dabb0"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:22afcb9f253dac0696b5a4be4a1c0f8762f8239e21b99680099abd9b2b1b2269"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e27ad930a842b4c5eb8ac0016b0a54f5aebbe679340c26101df33424142c143c"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1f79682fbe303db92bc2b1136016a38a42e835d932bab5b3b1bfcfbf0640e519"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b261ccdec7821281dade748d088bb6e9b69e6d15b30652b74cbbac25e280b796"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:122c7fa62b130ed55f8f285bfd56d5f4b4a5b503609d181f9ad85e55c89f4185"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:d0eccceffcb53201b5bfebb52600a5fb483a20b61da9dbc885f8b103cbe7598c"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:9f96df6923e21816da7e0ad3fd47dd8f94b2a5ce594e00677c0013018b813458"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:7f04c839ed0b6b98b1a7501a002144b76c18fb1c1850c8b98d458ac269e26ed2"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:34d1c8da1e78d2e001f363791c98a272bb734000fcef47a491c1e3b0505657a8"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ff8fa367d09b717b2a17a052544193ad76cd49979c805768879cb63d9ca50561"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-win32.whl", hash = "sha256:aed38f6e4fb3f5d6bf81bfa990a07806be9d83cf7bacef998ab1a9bd660a581f"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-win_amd64.whl", hash = "sha256:b01b88d45a6fcb69667cd6d2f7a9aeb4bf53760d7fc536bf679ec94fe9f3ff3d"}, - {file = "charset_normalizer-3.3.2-py3-none-any.whl", hash = "sha256:3e4d1f6587322d2788836a99c69062fbb091331ec940e02d12d179c1d53e25fc"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:4f9fc98dad6c2eaa32fc3af1417d95b5e3d08aff968df0cd320066def971f9a6"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0de7b687289d3c1b3e8660d0741874abe7888100efe14bd0f9fd7141bcbda92b"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5ed2e36c3e9b4f21dd9422f6893dec0abf2cca553af509b10cd630f878d3eb99"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:40d3ff7fc90b98c637bda91c89d51264a3dcf210cade3a2c6f838c7268d7a4ca"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1110e22af8ca26b90bd6364fe4c763329b0ebf1ee213ba32b68c73de5752323d"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:86f4e8cca779080f66ff4f191a685ced73d2f72d50216f7112185dc02b90b9b7"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f683ddc7eedd742e2889d2bfb96d69573fde1d92fcb811979cdb7165bb9c7d3"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:27623ba66c183eca01bf9ff833875b459cad267aeeb044477fedac35e19ba907"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:f606a1881d2663630ea5b8ce2efe2111740df4b687bd78b34a8131baa007f79b"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:0b309d1747110feb25d7ed6b01afdec269c647d382c857ef4663bbe6ad95a912"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:136815f06a3ae311fae551c3df1f998a1ebd01ddd424aa5603a4336997629e95"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:14215b71a762336254351b00ec720a8e85cada43b987da5a042e4ce3e82bd68e"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:79983512b108e4a164b9c8d34de3992f76d48cadc9554c9e60b43f308988aabe"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-win32.whl", hash = "sha256:c94057af19bc953643a33581844649a7fdab902624d2eb739738a30e2b3e60fc"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-win_amd64.whl", hash = "sha256:55f56e2ebd4e3bc50442fbc0888c9d8c94e4e06a933804e2af3e89e2f9c1c749"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:0d99dd8ff461990f12d6e42c7347fd9ab2532fb70e9621ba520f9e8637161d7c"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c57516e58fd17d03ebe67e181a4e4e2ccab1168f8c2976c6a334d4f819fe5944"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:6dba5d19c4dfab08e58d5b36304b3f92f3bd5d42c1a3fa37b5ba5cdf6dfcbcee"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bf4475b82be41b07cc5e5ff94810e6a01f276e37c2d55571e3fe175e467a1a1c"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ce031db0408e487fd2775d745ce30a7cd2923667cf3b69d48d219f1d8f5ddeb6"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8ff4e7cdfdb1ab5698e675ca622e72d58a6fa2a8aa58195de0c0061288e6e3ea"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3710a9751938947e6327ea9f3ea6332a09bf0ba0c09cae9cb1f250bd1f1549bc"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:82357d85de703176b5587dbe6ade8ff67f9f69a41c0733cf2425378b49954de5"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:47334db71978b23ebcf3c0f9f5ee98b8d65992b65c9c4f2d34c2eaf5bcaf0594"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:8ce7fd6767a1cc5a92a639b391891bf1c268b03ec7e021c7d6d902285259685c"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:f1a2f519ae173b5b6a2c9d5fa3116ce16e48b3462c8b96dfdded11055e3d6365"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:63bc5c4ae26e4bc6be6469943b8253c0fd4e4186c43ad46e713ea61a0ba49129"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:bcb4f8ea87d03bc51ad04add8ceaf9b0f085ac045ab4d74e73bbc2dc033f0236"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-win32.whl", hash = "sha256:9ae4ef0b3f6b41bad6366fb0ea4fc1d7ed051528e113a60fa2a65a9abb5b1d99"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-win_amd64.whl", hash = "sha256:cee4373f4d3ad28f1ab6290684d8e2ebdb9e7a1b74fdc39e4c211995f77bec27"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:0713f3adb9d03d49d365b70b84775d0a0d18e4ab08d12bc46baa6132ba78aaf6"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:de7376c29d95d6719048c194a9cf1a1b0393fbe8488a22008610b0361d834ecf"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:4a51b48f42d9358460b78725283f04bddaf44a9358197b889657deba38f329db"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b295729485b06c1a0683af02a9e42d2caa9db04a373dc38a6a58cdd1e8abddf1"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ee803480535c44e7f5ad00788526da7d85525cfefaf8acf8ab9a310000be4b03"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3d59d125ffbd6d552765510e3f31ed75ebac2c7470c7274195b9161a32350284"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8cda06946eac330cbe6598f77bb54e690b4ca93f593dee1568ad22b04f347c15"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:07afec21bbbbf8a5cc3651aa96b980afe2526e7f048fdfb7f1014d84acc8b6d8"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6b40e8d38afe634559e398cc32b1472f376a4099c75fe6299ae607e404c033b2"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:b8dcd239c743aa2f9c22ce674a145e0a25cb1566c495928440a181ca1ccf6719"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:84450ba661fb96e9fd67629b93d2941c871ca86fc38d835d19d4225ff946a631"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:44aeb140295a2f0659e113b31cfe92c9061622cadbc9e2a2f7b8ef6b1e29ef4b"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:1db4e7fefefd0f548d73e2e2e041f9df5c59e178b4c72fbac4cc6f535cfb1565"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-win32.whl", hash = "sha256:5726cf76c982532c1863fb64d8c6dd0e4c90b6ece9feb06c9f202417a31f7dd7"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-win_amd64.whl", hash = "sha256:b197e7094f232959f8f20541ead1d9862ac5ebea1d58e9849c1bf979255dfac9"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:dd4eda173a9fcccb5f2e2bd2a9f423d180194b1bf17cf59e3269899235b2a114"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e9e3c4c9e1ed40ea53acf11e2a386383c3304212c965773704e4603d589343ed"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:92a7e36b000bf022ef3dbb9c46bfe2d52c047d5e3f3343f43204263c5addc250"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:54b6a92d009cbe2fb11054ba694bc9e284dad30a26757b1e372a1fdddaf21920"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ffd9493de4c922f2a38c2bf62b831dcec90ac673ed1ca182fe11b4d8e9f2a64"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:35c404d74c2926d0287fbd63ed5d27eb911eb9e4a3bb2c6d294f3cfd4a9e0c23"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4796efc4faf6b53a18e3d46343535caed491776a22af773f366534056c4e1fbc"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e7fdd52961feb4c96507aa649550ec2a0d527c086d284749b2f582f2d40a2e0d"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:92db3c28b5b2a273346bebb24857fda45601aef6ae1c011c0a997106581e8a88"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:ab973df98fc99ab39080bfb0eb3a925181454d7c3ac8a1e695fddfae696d9e90"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:4b67fdab07fdd3c10bb21edab3cbfe8cf5696f453afce75d815d9d7223fbe88b"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:aa41e526a5d4a9dfcfbab0716c7e8a1b215abd3f3df5a45cf18a12721d31cb5d"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ffc519621dce0c767e96b9c53f09c5d215578e10b02c285809f76509a3931482"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-win32.whl", hash = "sha256:f19c1585933c82098c2a520f8ec1227f20e339e33aca8fa6f956f6691b784e67"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-win_amd64.whl", hash = "sha256:707b82d19e65c9bd28b81dde95249b07bf9f5b90ebe1ef17d9b57473f8a64b7b"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:dbe03226baf438ac4fda9e2d0715022fd579cb641c4cf639fa40d53b2fe6f3e2"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dd9a8bd8900e65504a305bf8ae6fa9fbc66de94178c420791d0293702fce2df7"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b8831399554b92b72af5932cdbbd4ddc55c55f631bb13ff8fe4e6536a06c5c51"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a14969b8691f7998e74663b77b4c36c0337cb1df552da83d5c9004a93afdb574"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dcaf7c1524c0542ee2fc82cc8ec337f7a9f7edee2532421ab200d2b920fc97cf"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:425c5f215d0eecee9a56cdb703203dda90423247421bf0d67125add85d0c4455"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-musllinux_1_2_aarch64.whl", hash = "sha256:d5b054862739d276e09928de37c79ddeec42a6e1bfc55863be96a36ba22926f6"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-musllinux_1_2_i686.whl", hash = "sha256:f3e73a4255342d4eb26ef6df01e3962e73aa29baa3124a8e824c5d3364a65748"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-musllinux_1_2_ppc64le.whl", hash = "sha256:2f6c34da58ea9c1a9515621f4d9ac379871a8f21168ba1b5e09d74250de5ad62"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-musllinux_1_2_s390x.whl", hash = "sha256:f09cb5a7bbe1ecae6e87901a2eb23e0256bb524a79ccc53eb0b7629fbe7677c4"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:0099d79bdfcf5c1f0c2c72f91516702ebf8b0b8ddd8905f97a8aecf49712c621"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-win32.whl", hash = "sha256:9c98230f5042f4945f957d006edccc2af1e03ed5e37ce7c373f00a5a4daa6149"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-win_amd64.whl", hash = "sha256:62f60aebecfc7f4b82e3f639a7d1433a20ec32824db2199a11ad4f5e146ef5ee"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:af73657b7a68211996527dbfeffbb0864e043d270580c5aef06dc4b659a4b578"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:cab5d0b79d987c67f3b9e9c53f54a61360422a5a0bc075f43cab5621d530c3b6"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:9289fd5dddcf57bab41d044f1756550f9e7cf0c8e373b8cdf0ce8773dc4bd417"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6b493a043635eb376e50eedf7818f2f322eabbaa974e948bd8bdd29eb7ef2a51"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9fa2566ca27d67c86569e8c85297aaf413ffab85a8960500f12ea34ff98e4c41"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a8e538f46104c815be19c975572d74afb53f29650ea2025bbfaef359d2de2f7f"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6fd30dc99682dc2c603c2b315bded2799019cea829f8bf57dc6b61efde6611c8"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2006769bd1640bdf4d5641c69a3d63b71b81445473cac5ded39740a226fa88ab"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:dc15e99b2d8a656f8e666854404f1ba54765871104e50c8e9813af8a7db07f12"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:ab2e5bef076f5a235c3774b4f4028a680432cded7cad37bba0fd90d64b187d19"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:4ec9dd88a5b71abfc74e9df5ebe7921c35cbb3b641181a531ca65cdb5e8e4dea"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:43193c5cda5d612f247172016c4bb71251c784d7a4d9314677186a838ad34858"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:aa693779a8b50cd97570e5a0f343538a8dbd3e496fa5dcb87e29406ad0299654"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-win32.whl", hash = "sha256:7706f5850360ac01d80c89bcef1640683cc12ed87f42579dab6c5d3ed6888613"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-win_amd64.whl", hash = "sha256:c3e446d253bd88f6377260d07c895816ebf33ffffd56c1c792b13bff9c3e1ade"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:980b4f289d1d90ca5efcf07958d3eb38ed9c0b7676bf2831a54d4f66f9c27dfa"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f28f891ccd15c514a0981f3b9db9aa23d62fe1a99997512b0491d2ed323d229a"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a8aacce6e2e1edcb6ac625fb0f8c3a9570ccc7bfba1f63419b3769ccf6a00ed0"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bd7af3717683bea4c87acd8c0d3d5b44d56120b26fd3f8a692bdd2d5260c620a"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5ff2ed8194587faf56555927b3aa10e6fb69d931e33953943bc4f837dfee2242"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e91f541a85298cf35433bf66f3fab2a4a2cff05c127eeca4af174f6d497f0d4b"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:309a7de0a0ff3040acaebb35ec45d18db4b28232f21998851cfa709eeff49d62"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:285e96d9d53422efc0d7a17c60e59f37fbf3dfa942073f666db4ac71e8d726d0"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:5d447056e2ca60382d460a604b6302d8db69476fd2015c81e7c35417cfabe4cd"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:20587d20f557fe189b7947d8e7ec5afa110ccf72a3128d61a2a387c3313f46be"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:130272c698667a982a5d0e626851ceff662565379baf0ff2cc58067b81d4f11d"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:ab22fbd9765e6954bc0bcff24c25ff71dcbfdb185fcdaca49e81bac68fe724d3"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:7782afc9b6b42200f7362858f9e73b1f8316afb276d316336c0ec3bd73312742"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-win32.whl", hash = "sha256:2de62e8801ddfff069cd5c504ce3bc9672b23266597d4e4f50eda28846c322f2"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-win_amd64.whl", hash = "sha256:95c3c157765b031331dd4db3c775e58deaee050a3042fcad72cbc4189d7c8dca"}, + {file = "charset_normalizer-3.4.0-py3-none-any.whl", hash = "sha256:fe9f97feb71aa9896b81973a7bbada8c49501dc73e58a10fcef6663af95e5079"}, + {file = "charset_normalizer-3.4.0.tar.gz", hash = "sha256:223217c3d4f82c3ac5e29032b3f1c2eb0fb591b72161f86d93f5719079dae93e"}, ] [[package]] @@ -567,83 +608,73 @@ files = [ [[package]] name = "coverage" -version = "7.6.1" +version = "7.6.4" description = "Code coverage measurement for Python" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "coverage-7.6.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b06079abebbc0e89e6163b8e8f0e16270124c154dc6e4a47b413dd538859af16"}, - {file = "coverage-7.6.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:cf4b19715bccd7ee27b6b120e7e9dd56037b9c0681dcc1adc9ba9db3d417fa36"}, - {file = "coverage-7.6.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e61c0abb4c85b095a784ef23fdd4aede7a2628478e7baba7c5e3deba61070a02"}, - {file = "coverage-7.6.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fd21f6ae3f08b41004dfb433fa895d858f3f5979e7762d052b12aef444e29afc"}, - {file = "coverage-7.6.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f59d57baca39b32db42b83b2a7ba6f47ad9c394ec2076b084c3f029b7afca23"}, - {file = "coverage-7.6.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:a1ac0ae2b8bd743b88ed0502544847c3053d7171a3cff9228af618a068ed9c34"}, - {file = "coverage-7.6.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e6a08c0be454c3b3beb105c0596ebdc2371fab6bb90c0c0297f4e58fd7e1012c"}, - {file = "coverage-7.6.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:f5796e664fe802da4f57a168c85359a8fbf3eab5e55cd4e4569fbacecc903959"}, - {file = "coverage-7.6.1-cp310-cp310-win32.whl", hash = "sha256:7bb65125fcbef8d989fa1dd0e8a060999497629ca5b0efbca209588a73356232"}, - {file = "coverage-7.6.1-cp310-cp310-win_amd64.whl", hash = "sha256:3115a95daa9bdba70aea750db7b96b37259a81a709223c8448fa97727d546fe0"}, - {file = "coverage-7.6.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:7dea0889685db8550f839fa202744652e87c60015029ce3f60e006f8c4462c93"}, - {file = "coverage-7.6.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ed37bd3c3b063412f7620464a9ac1314d33100329f39799255fb8d3027da50d3"}, - {file = "coverage-7.6.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d85f5e9a5f8b73e2350097c3756ef7e785f55bd71205defa0bfdaf96c31616ff"}, - {file = "coverage-7.6.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9bc572be474cafb617672c43fe989d6e48d3c83af02ce8de73fff1c6bb3c198d"}, - {file = "coverage-7.6.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0c0420b573964c760df9e9e86d1a9a622d0d27f417e1a949a8a66dd7bcee7bc6"}, - {file = "coverage-7.6.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1f4aa8219db826ce6be7099d559f8ec311549bfc4046f7f9fe9b5cea5c581c56"}, - {file = "coverage-7.6.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:fc5a77d0c516700ebad189b587de289a20a78324bc54baee03dd486f0855d234"}, - {file = "coverage-7.6.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b48f312cca9621272ae49008c7f613337c53fadca647d6384cc129d2996d1133"}, - {file = "coverage-7.6.1-cp311-cp311-win32.whl", hash = "sha256:1125ca0e5fd475cbbba3bb67ae20bd2c23a98fac4e32412883f9bcbaa81c314c"}, - {file = "coverage-7.6.1-cp311-cp311-win_amd64.whl", hash = "sha256:8ae539519c4c040c5ffd0632784e21b2f03fc1340752af711f33e5be83a9d6c6"}, - {file = "coverage-7.6.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:95cae0efeb032af8458fc27d191f85d1717b1d4e49f7cb226cf526ff28179778"}, - {file = "coverage-7.6.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5621a9175cf9d0b0c84c2ef2b12e9f5f5071357c4d2ea6ca1cf01814f45d2391"}, - {file = "coverage-7.6.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:260933720fdcd75340e7dbe9060655aff3af1f0c5d20f46b57f262ab6c86a5e8"}, - {file = "coverage-7.6.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:07e2ca0ad381b91350c0ed49d52699b625aab2b44b65e1b4e02fa9df0e92ad2d"}, - {file = "coverage-7.6.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c44fee9975f04b33331cb8eb272827111efc8930cfd582e0320613263ca849ca"}, - {file = "coverage-7.6.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:877abb17e6339d96bf08e7a622d05095e72b71f8afd8a9fefc82cf30ed944163"}, - {file = "coverage-7.6.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:3e0cadcf6733c09154b461f1ca72d5416635e5e4ec4e536192180d34ec160f8a"}, - {file = "coverage-7.6.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:c3c02d12f837d9683e5ab2f3d9844dc57655b92c74e286c262e0fc54213c216d"}, - {file = "coverage-7.6.1-cp312-cp312-win32.whl", hash = "sha256:e05882b70b87a18d937ca6768ff33cc3f72847cbc4de4491c8e73880766718e5"}, - {file = "coverage-7.6.1-cp312-cp312-win_amd64.whl", hash = "sha256:b5d7b556859dd85f3a541db6a4e0167b86e7273e1cdc973e5b175166bb634fdb"}, - {file = "coverage-7.6.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:a4acd025ecc06185ba2b801f2de85546e0b8ac787cf9d3b06e7e2a69f925b106"}, - {file = "coverage-7.6.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a6d3adcf24b624a7b778533480e32434a39ad8fa30c315208f6d3e5542aeb6e9"}, - {file = "coverage-7.6.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d0c212c49b6c10e6951362f7c6df3329f04c2b1c28499563d4035d964ab8e08c"}, - {file = "coverage-7.6.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6e81d7a3e58882450ec4186ca59a3f20a5d4440f25b1cff6f0902ad890e6748a"}, - {file = "coverage-7.6.1-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:78b260de9790fd81e69401c2dc8b17da47c8038176a79092a89cb2b7d945d060"}, - {file = "coverage-7.6.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a78d169acd38300060b28d600344a803628c3fd585c912cacc9ea8790fe96862"}, - {file = "coverage-7.6.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:2c09f4ce52cb99dd7505cd0fc8e0e37c77b87f46bc9c1eb03fe3bc9991085388"}, - {file = "coverage-7.6.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6878ef48d4227aace338d88c48738a4258213cd7b74fd9a3d4d7582bb1d8a155"}, - {file = "coverage-7.6.1-cp313-cp313-win32.whl", hash = "sha256:44df346d5215a8c0e360307d46ffaabe0f5d3502c8a1cefd700b34baf31d411a"}, - {file = "coverage-7.6.1-cp313-cp313-win_amd64.whl", hash = "sha256:8284cf8c0dd272a247bc154eb6c95548722dce90d098c17a883ed36e67cdb129"}, - {file = "coverage-7.6.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:d3296782ca4eab572a1a4eca686d8bfb00226300dcefdf43faa25b5242ab8a3e"}, - {file = "coverage-7.6.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:502753043567491d3ff6d08629270127e0c31d4184c4c8d98f92c26f65019962"}, - {file = "coverage-7.6.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6a89ecca80709d4076b95f89f308544ec8f7b4727e8a547913a35f16717856cb"}, - {file = "coverage-7.6.1-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a318d68e92e80af8b00fa99609796fdbcdfef3629c77c6283566c6f02c6d6704"}, - {file = "coverage-7.6.1-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:13b0a73a0896988f053e4fbb7de6d93388e6dd292b0d87ee51d106f2c11b465b"}, - {file = "coverage-7.6.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:4421712dbfc5562150f7554f13dde997a2e932a6b5f352edcce948a815efee6f"}, - {file = "coverage-7.6.1-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:166811d20dfea725e2e4baa71fffd6c968a958577848d2131f39b60043400223"}, - {file = "coverage-7.6.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:225667980479a17db1048cb2bf8bfb39b8e5be8f164b8f6628b64f78a72cf9d3"}, - {file = "coverage-7.6.1-cp313-cp313t-win32.whl", hash = "sha256:170d444ab405852903b7d04ea9ae9b98f98ab6d7e63e1115e82620807519797f"}, - {file = "coverage-7.6.1-cp313-cp313t-win_amd64.whl", hash = "sha256:b9f222de8cded79c49bf184bdbc06630d4c58eec9459b939b4a690c82ed05657"}, - {file = "coverage-7.6.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6db04803b6c7291985a761004e9060b2bca08da6d04f26a7f2294b8623a0c1a0"}, - {file = "coverage-7.6.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:f1adfc8ac319e1a348af294106bc6a8458a0f1633cc62a1446aebc30c5fa186a"}, - {file = "coverage-7.6.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a95324a9de9650a729239daea117df21f4b9868ce32e63f8b650ebe6cef5595b"}, - {file = "coverage-7.6.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b43c03669dc4618ec25270b06ecd3ee4fa94c7f9b3c14bae6571ca00ef98b0d3"}, - {file = "coverage-7.6.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8929543a7192c13d177b770008bc4e8119f2e1f881d563fc6b6305d2d0ebe9de"}, - {file = "coverage-7.6.1-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:a09ece4a69cf399510c8ab25e0950d9cf2b42f7b3cb0374f95d2e2ff594478a6"}, - {file = "coverage-7.6.1-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:9054a0754de38d9dbd01a46621636689124d666bad1936d76c0341f7d71bf569"}, - {file = "coverage-7.6.1-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:0dbde0f4aa9a16fa4d754356a8f2e36296ff4d83994b2c9d8398aa32f222f989"}, - {file = "coverage-7.6.1-cp38-cp38-win32.whl", hash = "sha256:da511e6ad4f7323ee5702e6633085fb76c2f893aaf8ce4c51a0ba4fc07580ea7"}, - {file = "coverage-7.6.1-cp38-cp38-win_amd64.whl", hash = "sha256:3f1156e3e8f2872197af3840d8ad307a9dd18e615dc64d9ee41696f287c57ad8"}, - {file = "coverage-7.6.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:abd5fd0db5f4dc9289408aaf34908072f805ff7792632250dcb36dc591d24255"}, - {file = "coverage-7.6.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:547f45fa1a93154bd82050a7f3cddbc1a7a4dd2a9bf5cb7d06f4ae29fe94eaf8"}, - {file = "coverage-7.6.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:645786266c8f18a931b65bfcefdbf6952dd0dea98feee39bd188607a9d307ed2"}, - {file = "coverage-7.6.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9e0b2df163b8ed01d515807af24f63de04bebcecbd6c3bfeff88385789fdf75a"}, - {file = "coverage-7.6.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:609b06f178fe8e9f89ef676532760ec0b4deea15e9969bf754b37f7c40326dbc"}, - {file = "coverage-7.6.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:702855feff378050ae4f741045e19a32d57d19f3e0676d589df0575008ea5004"}, - {file = "coverage-7.6.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:2bdb062ea438f22d99cba0d7829c2ef0af1d768d1e4a4f528087224c90b132cb"}, - {file = "coverage-7.6.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:9c56863d44bd1c4fe2abb8a4d6f5371d197f1ac0ebdee542f07f35895fc07f36"}, - {file = "coverage-7.6.1-cp39-cp39-win32.whl", hash = "sha256:6e2cd258d7d927d09493c8df1ce9174ad01b381d4729a9d8d4e38670ca24774c"}, - {file = "coverage-7.6.1-cp39-cp39-win_amd64.whl", hash = "sha256:06a737c882bd26d0d6ee7269b20b12f14a8704807a01056c80bb881a4b2ce6ca"}, - {file = "coverage-7.6.1-pp38.pp39.pp310-none-any.whl", hash = "sha256:e9a6e0eb86070e8ccaedfbd9d38fec54864f3125ab95419970575b42af7541df"}, - {file = "coverage-7.6.1.tar.gz", hash = "sha256:953510dfb7b12ab69d20135a0662397f077c59b1e6379a768e97c59d852ee51d"}, + {file = "coverage-7.6.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5f8ae553cba74085db385d489c7a792ad66f7f9ba2ee85bfa508aeb84cf0ba07"}, + {file = "coverage-7.6.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8165b796df0bd42e10527a3f493c592ba494f16ef3c8b531288e3d0d72c1f6f0"}, + {file = "coverage-7.6.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c7c8b95bf47db6d19096a5e052ffca0a05f335bc63cef281a6e8fe864d450a72"}, + {file = "coverage-7.6.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8ed9281d1b52628e81393f5eaee24a45cbd64965f41857559c2b7ff19385df51"}, + {file = "coverage-7.6.4-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0809082ee480bb8f7416507538243c8863ac74fd8a5d2485c46f0f7499f2b491"}, + {file = "coverage-7.6.4-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:d541423cdd416b78626b55f123412fcf979d22a2c39fce251b350de38c15c15b"}, + {file = "coverage-7.6.4-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:58809e238a8a12a625c70450b48e8767cff9eb67c62e6154a642b21ddf79baea"}, + {file = "coverage-7.6.4-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:c9b8e184898ed014884ca84c70562b4a82cbc63b044d366fedc68bc2b2f3394a"}, + {file = "coverage-7.6.4-cp310-cp310-win32.whl", hash = "sha256:6bd818b7ea14bc6e1f06e241e8234508b21edf1b242d49831831a9450e2f35fa"}, + {file = "coverage-7.6.4-cp310-cp310-win_amd64.whl", hash = "sha256:06babbb8f4e74b063dbaeb74ad68dfce9186c595a15f11f5d5683f748fa1d172"}, + {file = "coverage-7.6.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:73d2b73584446e66ee633eaad1a56aad577c077f46c35ca3283cd687b7715b0b"}, + {file = "coverage-7.6.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:51b44306032045b383a7a8a2c13878de375117946d68dcb54308111f39775a25"}, + {file = "coverage-7.6.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0b3fb02fe73bed561fa12d279a417b432e5b50fe03e8d663d61b3d5990f29546"}, + {file = "coverage-7.6.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ed8fe9189d2beb6edc14d3ad19800626e1d9f2d975e436f84e19efb7fa19469b"}, + {file = "coverage-7.6.4-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b369ead6527d025a0fe7bd3864e46dbee3aa8f652d48df6174f8d0bac9e26e0e"}, + {file = "coverage-7.6.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:ade3ca1e5f0ff46b678b66201f7ff477e8fa11fb537f3b55c3f0568fbfe6e718"}, + {file = "coverage-7.6.4-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:27fb4a050aaf18772db513091c9c13f6cb94ed40eacdef8dad8411d92d9992db"}, + {file = "coverage-7.6.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:4f704f0998911abf728a7783799444fcbbe8261c4a6c166f667937ae6a8aa522"}, + {file = "coverage-7.6.4-cp311-cp311-win32.whl", hash = "sha256:29155cd511ee058e260db648b6182c419422a0d2e9a4fa44501898cf918866cf"}, + {file = "coverage-7.6.4-cp311-cp311-win_amd64.whl", hash = "sha256:8902dd6a30173d4ef09954bfcb24b5d7b5190cf14a43170e386979651e09ba19"}, + {file = "coverage-7.6.4-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:12394842a3a8affa3ba62b0d4ab7e9e210c5e366fbac3e8b2a68636fb19892c2"}, + {file = "coverage-7.6.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2b6b4c83d8e8ea79f27ab80778c19bc037759aea298da4b56621f4474ffeb117"}, + {file = "coverage-7.6.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1d5b8007f81b88696d06f7df0cb9af0d3b835fe0c8dbf489bad70b45f0e45613"}, + {file = "coverage-7.6.4-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b57b768feb866f44eeed9f46975f3d6406380275c5ddfe22f531a2bf187eda27"}, + {file = "coverage-7.6.4-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5915fcdec0e54ee229926868e9b08586376cae1f5faa9bbaf8faf3561b393d52"}, + {file = "coverage-7.6.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:0b58c672d14f16ed92a48db984612f5ce3836ae7d72cdd161001cc54512571f2"}, + {file = "coverage-7.6.4-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:2fdef0d83a2d08d69b1f2210a93c416d54e14d9eb398f6ab2f0a209433db19e1"}, + {file = "coverage-7.6.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:8cf717ee42012be8c0cb205dbbf18ffa9003c4cbf4ad078db47b95e10748eec5"}, + {file = "coverage-7.6.4-cp312-cp312-win32.whl", hash = "sha256:7bb92c539a624cf86296dd0c68cd5cc286c9eef2d0c3b8b192b604ce9de20a17"}, + {file = "coverage-7.6.4-cp312-cp312-win_amd64.whl", hash = "sha256:1032e178b76a4e2b5b32e19d0fd0abbce4b58e77a1ca695820d10e491fa32b08"}, + {file = "coverage-7.6.4-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:023bf8ee3ec6d35af9c1c6ccc1d18fa69afa1cb29eaac57cb064dbb262a517f9"}, + {file = "coverage-7.6.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:b0ac3d42cb51c4b12df9c5f0dd2f13a4f24f01943627120ec4d293c9181219ba"}, + {file = "coverage-7.6.4-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f8fe4984b431f8621ca53d9380901f62bfb54ff759a1348cd140490ada7b693c"}, + {file = "coverage-7.6.4-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5fbd612f8a091954a0c8dd4c0b571b973487277d26476f8480bfa4b2a65b5d06"}, + {file = "coverage-7.6.4-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dacbc52de979f2823a819571f2e3a350a7e36b8cb7484cdb1e289bceaf35305f"}, + {file = "coverage-7.6.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:dab4d16dfef34b185032580e2f2f89253d302facba093d5fa9dbe04f569c4f4b"}, + {file = "coverage-7.6.4-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:862264b12ebb65ad8d863d51f17758b1684560b66ab02770d4f0baf2ff75da21"}, + {file = "coverage-7.6.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:5beb1ee382ad32afe424097de57134175fea3faf847b9af002cc7895be4e2a5a"}, + {file = "coverage-7.6.4-cp313-cp313-win32.whl", hash = "sha256:bf20494da9653f6410213424f5f8ad0ed885e01f7e8e59811f572bdb20b8972e"}, + {file = "coverage-7.6.4-cp313-cp313-win_amd64.whl", hash = "sha256:182e6cd5c040cec0a1c8d415a87b67ed01193ed9ad458ee427741c7d8513d963"}, + {file = "coverage-7.6.4-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:a181e99301a0ae128493a24cfe5cfb5b488c4e0bf2f8702091473d033494d04f"}, + {file = "coverage-7.6.4-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:df57bdbeffe694e7842092c5e2e0bc80fff7f43379d465f932ef36f027179806"}, + {file = "coverage-7.6.4-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0bcd1069e710600e8e4cf27f65c90c7843fa8edfb4520fb0ccb88894cad08b11"}, + {file = "coverage-7.6.4-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:99b41d18e6b2a48ba949418db48159d7a2e81c5cc290fc934b7d2380515bd0e3"}, + {file = "coverage-7.6.4-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a6b1e54712ba3474f34b7ef7a41e65bd9037ad47916ccb1cc78769bae324c01a"}, + {file = "coverage-7.6.4-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:53d202fd109416ce011578f321460795abfe10bb901b883cafd9b3ef851bacfc"}, + {file = "coverage-7.6.4-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:c48167910a8f644671de9f2083a23630fbf7a1cb70ce939440cd3328e0919f70"}, + {file = "coverage-7.6.4-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:cc8ff50b50ce532de2fa7a7daae9dd12f0a699bfcd47f20945364e5c31799fef"}, + {file = "coverage-7.6.4-cp313-cp313t-win32.whl", hash = "sha256:b8d3a03d9bfcaf5b0141d07a88456bb6a4c3ce55c080712fec8418ef3610230e"}, + {file = "coverage-7.6.4-cp313-cp313t-win_amd64.whl", hash = "sha256:f3ddf056d3ebcf6ce47bdaf56142af51bb7fad09e4af310241e9db7a3a8022e1"}, + {file = "coverage-7.6.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9cb7fa111d21a6b55cbf633039f7bc2749e74932e3aa7cb7333f675a58a58bf3"}, + {file = "coverage-7.6.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:11a223a14e91a4693d2d0755c7a043db43d96a7450b4f356d506c2562c48642c"}, + {file = "coverage-7.6.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a413a096c4cbac202433c850ee43fa326d2e871b24554da8327b01632673a076"}, + {file = "coverage-7.6.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:00a1d69c112ff5149cabe60d2e2ee948752c975d95f1e1096742e6077affd376"}, + {file = "coverage-7.6.4-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1f76846299ba5c54d12c91d776d9605ae33f8ae2b9d1d3c3703cf2db1a67f2c0"}, + {file = "coverage-7.6.4-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:fe439416eb6380de434886b00c859304338f8b19f6f54811984f3420a2e03858"}, + {file = "coverage-7.6.4-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:0294ca37f1ba500667b1aef631e48d875ced93ad5e06fa665a3295bdd1d95111"}, + {file = "coverage-7.6.4-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:6f01ba56b1c0e9d149f9ac85a2f999724895229eb36bd997b61e62999e9b0901"}, + {file = "coverage-7.6.4-cp39-cp39-win32.whl", hash = "sha256:bc66f0bf1d7730a17430a50163bb264ba9ded56739112368ba985ddaa9c3bd09"}, + {file = "coverage-7.6.4-cp39-cp39-win_amd64.whl", hash = "sha256:c481b47f6b5845064c65a7bc78bc0860e635a9b055af0df46fdf1c58cebf8e8f"}, + {file = "coverage-7.6.4-pp39.pp310-none-any.whl", hash = "sha256:3c65d37f3a9ebb703e710befdc489a38683a5b152242664b973a7b7b22348a4e"}, + {file = "coverage-7.6.4.tar.gz", hash = "sha256:29fc0f17b1d3fea332f8001d4558f8214af7f1d87a345f3a133c901d60347c73"}, ] [package.dependencies] @@ -715,20 +746,6 @@ ssh = ["bcrypt (>=3.1.5)"] test = ["certifi", "cryptography-vectors (==43.0.1)", "pretend", "pytest (>=6.2.0)", "pytest-benchmark", "pytest-cov", "pytest-xdist"] test-randomorder = ["pytest-randomly"] -[[package]] -name = "cxxfilt" -version = "0.3.0" -description = "Python interface to c++filt / abi::__cxa_demangle" -optional = false -python-versions = "*" -files = [ - {file = "cxxfilt-0.3.0-py2.py3-none-any.whl", hash = "sha256:774e85a8d0157775ed43276d89397d924b104135762d86b3a95f81f203094e07"}, - {file = "cxxfilt-0.3.0.tar.gz", hash = "sha256:7df6464ba5e8efbf0d8974c0b2c78b32546676f06059a83515dbdfa559b34214"}, -] - -[package.extras] -test = ["pytest (>=3.0.0)"] - [[package]] name = "cython" version = "0.29.24" @@ -841,13 +858,13 @@ tests = ["beautifulsoup4", "black", "lxml", "pytest"] [[package]] name = "distlib" -version = "0.3.8" +version = "0.3.9" description = "Distribution utilities" optional = false python-versions = "*" files = [ - {file = "distlib-0.3.8-py2.py3-none-any.whl", hash = "sha256:034db59a0b96f8ca18035f36290806a9a6e6bd9d1ff91e45a7f172eb17e51784"}, - {file = "distlib-0.3.8.tar.gz", hash = "sha256:1530ea13e350031b6312d8580ddb6b27a104275a31106523b8f123787f494f64"}, + {file = "distlib-0.3.9-py2.py3-none-any.whl", hash = "sha256:47f8c22fd27c27e25a65601af709b38e4f0a45ea4fc2e710f65755fa8caaaf87"}, + {file = "distlib-0.3.9.tar.gz", hash = "sha256:a60f20dea646b8a33f3e7772f74dc0b2d0772d2837ee1342a00645c81edf9403"}, ] [[package]] @@ -998,13 +1015,13 @@ dev = ["black (==22.12.0)", "dnfile (==0.12.0)", "hexdump (==3.3.0)", "isort (== [[package]] name = "dnfile" -version = "0.15.0" +version = "0.15.1" description = "Parse .NET executable files." optional = false python-versions = ">=3.8" files = [ - {file = "dnfile-0.15.0-py3-none-any.whl", hash = "sha256:d60239de76035bed22f3c131925cf8d484f44a9da03c19659a01a615309add55"}, - {file = "dnfile-0.15.0.tar.gz", hash = "sha256:e4ae8803a59d8f845c11524e8b007104b43c90adc2fb0a81dcdc2972c47dfc80"}, + {file = "dnfile-0.15.1-py3-none-any.whl", hash = "sha256:585c8e3e4a29824402430a0a8b7e7ae82c040fc17eeb3a06758fdceebe2d923e"}, + {file = "dnfile-0.15.1.tar.gz", hash = "sha256:1529cf0f976b1382f60a3c56b2e0def90f3486e41193ffd34677e74563c8426c"}, ] [package.dependencies] @@ -1096,45 +1113,6 @@ docs = ["furo (>=2024.8.6)", "sphinx (>=8.0.2)", "sphinx-autodoc-typehints (>=2. testing = ["covdefaults (>=2.3)", "coverage (>=7.6.1)", "diff-cover (>=9.2)", "pytest (>=8.3.3)", "pytest-asyncio (>=0.24)", "pytest-cov (>=5)", "pytest-mock (>=3.14)", "pytest-timeout (>=2.3.1)", "virtualenv (>=20.26.4)"] typing = ["typing-extensions (>=4.12.2)"] -[[package]] -name = "flare-capa" -version = "7.3.0" -description = "The FLARE team's open-source tool to identify capabilities in executable files." -optional = false -python-versions = ">=3.8" -files = [ - {file = "flare_capa-7.3.0-py3-none-any.whl", hash = "sha256:f7a7f35f4dce1aca723fcc792a6afbc384a696d889ef891649dc823d948e43ff"}, - {file = "flare_capa-7.3.0.tar.gz", hash = "sha256:21be4c9ce0af093bb0590ec7fd807096483d16c68753a375576420fe8ebcfecf"}, -] - -[package.dependencies] -colorama = ">=0.4" -dncil = ">=1.0.2" -dnfile = ">=0.15.0" -humanize = ">=4" -ida-settings = ">=2" -msgspec = ">=0.18.6" -networkx = ">=3,<3.2" -pefile = ">=2023.2.7" -protobuf = ">=5" -pydantic = ">=2" -pyelftools = ">=0.31" -pyyaml = ">=6" -rich = ">=13" -"ruamel.yaml" = ">=0.18" -tabulate = ">=0.9" -termcolor = ">=2" -tqdm = ">=4" -viv-utils = {version = ">=0.7.9", extras = ["flirt"]} -vivisect = ">=1.1.1" -wcwidth = ">=0.2" -xmltodict = ">=0.13.0" - -[package.extras] -build = ["build (==1.2.2)", "pyinstaller (==6.10.0)", "setuptools (==70.0.0)"] -dev = ["PyGithub (==2.4.0)", "black (==24.8.0)", "deptry (==0.20.0)", "flake8 (==7.1.1)", "flake8-bugbear (==24.8.19)", "flake8-comprehensions (==3.15.0)", "flake8-copyright (==0.2.4)", "flake8-encodings (==0.5.1)", "flake8-logging-format (==0.9.0)", "flake8-no-implicit-concat (==0.3.5)", "flake8-print (==5.0.0)", "flake8-simplify (==0.21.0)", "flake8-todos (==0.3.1)", "flake8-use-pathlib (==0.3.0)", "isort (==5.13.2)", "mypy (==1.11.2)", "mypy-protobuf (==3.6.0)", "pre-commit (==3.5.0)", "pytest (==8.0.0)", "pytest-cov (==5.0.0)", "pytest-instafail (==0.5.0)", "pytest-sugar (==1.0.0)", "ruff (==0.6.4)", "types-PyYAML (==6.0.8)", "types-backports (==0.1.3)", "types-colorama (==0.4.15.11)", "types-protobuf (==5.27.0.20240907)", "types-psutil (==6.0.0.20240901)", "types-requests (==2.32.0.20240712)", "types-tabulate (==0.9.0.20240106)", "types-termcolor (==1.1.4)"] -scripts = ["jschema-to-python (==1.2.3)", "psutil (==6.0.0)", "requests (==2.32.3)", "sarif-om (==1.0.4)", "stix2 (==3.0.1)"] - [[package]] name = "freezegun" version = "1.5.1" @@ -1159,17 +1137,6 @@ files = [ {file = "func_timeout-4.3.5.tar.gz", hash = "sha256:74cd3c428ec94f4edfba81f9b2f14904846d5ffccc27c92433b8b5939b5575dd"}, ] -[[package]] -name = "funcy" -version = "2.0" -description = "A fancy and practical functional tools" -optional = false -python-versions = "*" -files = [ - {file = "funcy-2.0-py2.py3-none-any.whl", hash = "sha256:53df23c8bb1651b12f095df764bfb057935d49537a56de211b098f4c79614bb0"}, - {file = "funcy-2.0.tar.gz", hash = "sha256:3963315d59d41c6f30c04bc910e10ab50a3ac4a225868bfa96feed133df075cb"}, -] - [[package]] name = "future" version = "1.0.0" @@ -1362,65 +1329,58 @@ files = [ [[package]] name = "httptools" -version = "0.6.1" +version = "0.6.4" description = "A collection of framework independent HTTP protocol utils." optional = false python-versions = ">=3.8.0" files = [ - {file = "httptools-0.6.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d2f6c3c4cb1948d912538217838f6e9960bc4a521d7f9b323b3da579cd14532f"}, - {file = "httptools-0.6.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:00d5d4b68a717765b1fabfd9ca755bd12bf44105eeb806c03d1962acd9b8e563"}, - {file = "httptools-0.6.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:639dc4f381a870c9ec860ce5c45921db50205a37cc3334e756269736ff0aac58"}, - {file = "httptools-0.6.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e57997ac7fb7ee43140cc03664de5f268813a481dff6245e0075925adc6aa185"}, - {file = "httptools-0.6.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:0ac5a0ae3d9f4fe004318d64b8a854edd85ab76cffbf7ef5e32920faef62f142"}, - {file = "httptools-0.6.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:3f30d3ce413088a98b9db71c60a6ada2001a08945cb42dd65a9a9fe228627658"}, - {file = "httptools-0.6.1-cp310-cp310-win_amd64.whl", hash = "sha256:1ed99a373e327f0107cb513b61820102ee4f3675656a37a50083eda05dc9541b"}, - {file = "httptools-0.6.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:7a7ea483c1a4485c71cb5f38be9db078f8b0e8b4c4dc0210f531cdd2ddac1ef1"}, - {file = "httptools-0.6.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:85ed077c995e942b6f1b07583e4eb0a8d324d418954fc6af913d36db7c05a5a0"}, - {file = "httptools-0.6.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8b0bb634338334385351a1600a73e558ce619af390c2b38386206ac6a27fecfc"}, - {file = "httptools-0.6.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7d9ceb2c957320def533671fc9c715a80c47025139c8d1f3797477decbc6edd2"}, - {file = "httptools-0.6.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:4f0f8271c0a4db459f9dc807acd0eadd4839934a4b9b892f6f160e94da309837"}, - {file = "httptools-0.6.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:6a4f5ccead6d18ec072ac0b84420e95d27c1cdf5c9f1bc8fbd8daf86bd94f43d"}, - {file = "httptools-0.6.1-cp311-cp311-win_amd64.whl", hash = "sha256:5cceac09f164bcba55c0500a18fe3c47df29b62353198e4f37bbcc5d591172c3"}, - {file = "httptools-0.6.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:75c8022dca7935cba14741a42744eee13ba05db00b27a4b940f0d646bd4d56d0"}, - {file = "httptools-0.6.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:48ed8129cd9a0d62cf4d1575fcf90fb37e3ff7d5654d3a5814eb3d55f36478c2"}, - {file = "httptools-0.6.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6f58e335a1402fb5a650e271e8c2d03cfa7cea46ae124649346d17bd30d59c90"}, - {file = "httptools-0.6.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:93ad80d7176aa5788902f207a4e79885f0576134695dfb0fefc15b7a4648d503"}, - {file = "httptools-0.6.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:9bb68d3a085c2174c2477eb3ffe84ae9fb4fde8792edb7bcd09a1d8467e30a84"}, - {file = "httptools-0.6.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:b512aa728bc02354e5ac086ce76c3ce635b62f5fbc32ab7082b5e582d27867bb"}, - {file = "httptools-0.6.1-cp312-cp312-win_amd64.whl", hash = "sha256:97662ce7fb196c785344d00d638fc9ad69e18ee4bfb4000b35a52efe5adcc949"}, - {file = "httptools-0.6.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:8e216a038d2d52ea13fdd9b9c9c7459fb80d78302b257828285eca1c773b99b3"}, - {file = "httptools-0.6.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:3e802e0b2378ade99cd666b5bffb8b2a7cc8f3d28988685dc300469ea8dd86cb"}, - {file = "httptools-0.6.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4bd3e488b447046e386a30f07af05f9b38d3d368d1f7b4d8f7e10af85393db97"}, - {file = "httptools-0.6.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fe467eb086d80217b7584e61313ebadc8d187a4d95bb62031b7bab4b205c3ba3"}, - {file = "httptools-0.6.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:3c3b214ce057c54675b00108ac42bacf2ab8f85c58e3f324a4e963bbc46424f4"}, - {file = "httptools-0.6.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:8ae5b97f690badd2ca27cbf668494ee1b6d34cf1c464271ef7bfa9ca6b83ffaf"}, - {file = "httptools-0.6.1-cp38-cp38-win_amd64.whl", hash = "sha256:405784577ba6540fa7d6ff49e37daf104e04f4b4ff2d1ac0469eaa6a20fde084"}, - {file = "httptools-0.6.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:95fb92dd3649f9cb139e9c56604cc2d7c7bf0fc2e7c8d7fbd58f96e35eddd2a3"}, - {file = "httptools-0.6.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:dcbab042cc3ef272adc11220517278519adf8f53fd3056d0e68f0a6f891ba94e"}, - {file = "httptools-0.6.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0cf2372e98406efb42e93bfe10f2948e467edfd792b015f1b4ecd897903d3e8d"}, - {file = "httptools-0.6.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:678fcbae74477a17d103b7cae78b74800d795d702083867ce160fc202104d0da"}, - {file = "httptools-0.6.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:e0b281cf5a125c35f7f6722b65d8542d2e57331be573e9e88bc8b0115c4a7a81"}, - {file = "httptools-0.6.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:95658c342529bba4e1d3d2b1a874db16c7cca435e8827422154c9da76ac4e13a"}, - {file = "httptools-0.6.1-cp39-cp39-win_amd64.whl", hash = "sha256:7ebaec1bf683e4bf5e9fbb49b8cc36da482033596a415b3e4ebab5a4c0d7ec5e"}, - {file = "httptools-0.6.1.tar.gz", hash = "sha256:c6e26c30455600b95d94b1b836085138e82f177351454ee841c148f93a9bad5a"}, + {file = "httptools-0.6.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:3c73ce323711a6ffb0d247dcd5a550b8babf0f757e86a52558fe5b86d6fefcc0"}, + {file = "httptools-0.6.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:345c288418f0944a6fe67be8e6afa9262b18c7626c3ef3c28adc5eabc06a68da"}, + {file = "httptools-0.6.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:deee0e3343f98ee8047e9f4c5bc7cedbf69f5734454a94c38ee829fb2d5fa3c1"}, + {file = "httptools-0.6.4-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ca80b7485c76f768a3bc83ea58373f8db7b015551117375e4918e2aa77ea9b50"}, + {file = "httptools-0.6.4-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:90d96a385fa941283ebd231464045187a31ad932ebfa541be8edf5b3c2328959"}, + {file = "httptools-0.6.4-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:59e724f8b332319e2875efd360e61ac07f33b492889284a3e05e6d13746876f4"}, + {file = "httptools-0.6.4-cp310-cp310-win_amd64.whl", hash = "sha256:c26f313951f6e26147833fc923f78f95604bbec812a43e5ee37f26dc9e5a686c"}, + {file = "httptools-0.6.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:f47f8ed67cc0ff862b84a1189831d1d33c963fb3ce1ee0c65d3b0cbe7b711069"}, + {file = "httptools-0.6.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:0614154d5454c21b6410fdf5262b4a3ddb0f53f1e1721cfd59d55f32138c578a"}, + {file = "httptools-0.6.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f8787367fbdfccae38e35abf7641dafc5310310a5987b689f4c32cc8cc3ee975"}, + {file = "httptools-0.6.4-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:40b0f7fe4fd38e6a507bdb751db0379df1e99120c65fbdc8ee6c1d044897a636"}, + {file = "httptools-0.6.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:40a5ec98d3f49904b9fe36827dcf1aadfef3b89e2bd05b0e35e94f97c2b14721"}, + {file = "httptools-0.6.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:dacdd3d10ea1b4ca9df97a0a303cbacafc04b5cd375fa98732678151643d4988"}, + {file = "httptools-0.6.4-cp311-cp311-win_amd64.whl", hash = "sha256:288cd628406cc53f9a541cfaf06041b4c71d751856bab45e3702191f931ccd17"}, + {file = "httptools-0.6.4-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:df017d6c780287d5c80601dafa31f17bddb170232d85c066604d8558683711a2"}, + {file = "httptools-0.6.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:85071a1e8c2d051b507161f6c3e26155b5c790e4e28d7f236422dbacc2a9cc44"}, + {file = "httptools-0.6.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69422b7f458c5af875922cdb5bd586cc1f1033295aa9ff63ee196a87519ac8e1"}, + {file = "httptools-0.6.4-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:16e603a3bff50db08cd578d54f07032ca1631450ceb972c2f834c2b860c28ea2"}, + {file = "httptools-0.6.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:ec4f178901fa1834d4a060320d2f3abc5c9e39766953d038f1458cb885f47e81"}, + {file = "httptools-0.6.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:f9eb89ecf8b290f2e293325c646a211ff1c2493222798bb80a530c5e7502494f"}, + {file = "httptools-0.6.4-cp312-cp312-win_amd64.whl", hash = "sha256:db78cb9ca56b59b016e64b6031eda5653be0589dba2b1b43453f6e8b405a0970"}, + {file = "httptools-0.6.4-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ade273d7e767d5fae13fa637f4d53b6e961fb7fd93c7797562663f0171c26660"}, + {file = "httptools-0.6.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:856f4bc0478ae143bad54a4242fccb1f3f86a6e1be5548fecfd4102061b3a083"}, + {file = "httptools-0.6.4-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:322d20ea9cdd1fa98bd6a74b77e2ec5b818abdc3d36695ab402a0de8ef2865a3"}, + {file = "httptools-0.6.4-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4d87b29bd4486c0093fc64dea80231f7c7f7eb4dc70ae394d70a495ab8436071"}, + {file = "httptools-0.6.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:342dd6946aa6bda4b8f18c734576106b8a31f2fe31492881a9a160ec84ff4bd5"}, + {file = "httptools-0.6.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4b36913ba52008249223042dca46e69967985fb4051951f94357ea681e1f5dc0"}, + {file = "httptools-0.6.4-cp313-cp313-win_amd64.whl", hash = "sha256:28908df1b9bb8187393d5b5db91435ccc9c8e891657f9cbb42a2541b44c82fc8"}, + {file = "httptools-0.6.4-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:d3f0d369e7ffbe59c4b6116a44d6a8eb4783aae027f2c0b366cf0aa964185dba"}, + {file = "httptools-0.6.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:94978a49b8f4569ad607cd4946b759d90b285e39c0d4640c6b36ca7a3ddf2efc"}, + {file = "httptools-0.6.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:40dc6a8e399e15ea525305a2ddba998b0af5caa2566bcd79dcbe8948181eeaff"}, + {file = "httptools-0.6.4-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ab9ba8dcf59de5181f6be44a77458e45a578fc99c31510b8c65b7d5acc3cf490"}, + {file = "httptools-0.6.4-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:fc411e1c0a7dcd2f902c7c48cf079947a7e65b5485dea9decb82b9105ca71a43"}, + {file = "httptools-0.6.4-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:d54efd20338ac52ba31e7da78e4a72570cf729fac82bc31ff9199bedf1dc7440"}, + {file = "httptools-0.6.4-cp38-cp38-win_amd64.whl", hash = "sha256:df959752a0c2748a65ab5387d08287abf6779ae9165916fe053e68ae1fbdc47f"}, + {file = "httptools-0.6.4-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:85797e37e8eeaa5439d33e556662cc370e474445d5fab24dcadc65a8ffb04003"}, + {file = "httptools-0.6.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:db353d22843cf1028f43c3651581e4bb49374d85692a85f95f7b9a130e1b2cab"}, + {file = "httptools-0.6.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d1ffd262a73d7c28424252381a5b854c19d9de5f56f075445d33919a637e3547"}, + {file = "httptools-0.6.4-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:703c346571fa50d2e9856a37d7cd9435a25e7fd15e236c397bf224afaa355fe9"}, + {file = "httptools-0.6.4-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:aafe0f1918ed07b67c1e838f950b1c1fabc683030477e60b335649b8020e1076"}, + {file = "httptools-0.6.4-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:0e563e54979e97b6d13f1bbc05a96109923e76b901f786a5eae36e99c01237bd"}, + {file = "httptools-0.6.4-cp39-cp39-win_amd64.whl", hash = "sha256:b799de31416ecc589ad79dd85a0b2657a8fe39327944998dea368c1d4c9e55e6"}, + {file = "httptools-0.6.4.tar.gz", hash = "sha256:4e93eee4add6493b59a5c514da98c939b244fce4a0d8879cd3f466562f4b7d5c"}, ] [package.extras] -test = ["Cython (>=0.29.24,<0.30.0)"] - -[[package]] -name = "humanize" -version = "4.10.0" -description = "Python humanize utilities" -optional = false -python-versions = ">=3.8" -files = [ - {file = "humanize-4.10.0-py3-none-any.whl", hash = "sha256:39e7ccb96923e732b5c2e27aeaa3b10a8dfeeba3eb965ba7b74a3eb0e30040a6"}, - {file = "humanize-4.10.0.tar.gz", hash = "sha256:06b6eb0293e4b85e8d385397c5868926820db32b9b654b932f57fa41c23c9978"}, -] - -[package.extras] -tests = ["freezegun", "pytest", "pytest-cov"] +test = ["Cython (>=0.29.24)"] [[package]] name = "hyperlink" @@ -1436,35 +1396,6 @@ files = [ [package.dependencies] idna = ">=2.5" -[[package]] -name = "ida-netnode" -version = "3.0" -description = "Humane API for storing and accessing persistent data in IDA Pro databases" -optional = false -python-versions = "*" -files = [ - {file = "ida-netnode-3.0.tar.gz", hash = "sha256:b7e1f2fbf57e3e104ed779d58e5f3f050aa48cce581bab8bf14ccee7a315e32e"}, - {file = "ida_netnode-3.0-py3-none-any.whl", hash = "sha256:b9d117703e076c9d219c9337d0b43d935b5102b5cb677835f7c9776a9f0340a5"}, -] - -[package.dependencies] -six = "*" - -[[package]] -name = "ida-settings" -version = "2.1.0" -description = "Fetch and set configuration values in IDA Pro IDAPython scripts" -optional = false -python-versions = "*" -files = [ - {file = "ida-settings-2.1.0.tar.gz", hash = "sha256:1371730b4e64bf388845b65a41bea094ebde8a5d3a05bdf4edf2f42aaba83262"}, - {file = "ida_settings-2.1.0-py2-none-any.whl", hash = "sha256:eab913b31ed0565aacea6d31976696c33b60c7e7bce3fccb75f32bef3878fc61"}, -] - -[package.dependencies] -ida-netnode = "*" -six = "*" - [[package]] name = "identify" version = "2.6.1" @@ -1537,19 +1468,6 @@ files = [ [package.dependencies] six = "*" -[[package]] -name = "intervaltree" -version = "3.1.0" -description = "Editable interval tree data structure for Python 2 and 3" -optional = false -python-versions = "*" -files = [ - {file = "intervaltree-3.1.0.tar.gz", hash = "sha256:902b1b88936918f9b2a19e0e5eb7ccb430ae45cde4f39ea4b36932920d33952d"}, -] - -[package.dependencies] -sortedcontainers = ">=2.0,<3.0" - [[package]] name = "isort" version = "5.13.2" @@ -1611,13 +1529,13 @@ yara-python = "*" [[package]] name = "mako" -version = "1.3.5" +version = "1.3.6" description = "A super-fast templating language that borrows the best ideas from the existing templating languages." optional = false python-versions = ">=3.8" files = [ - {file = "Mako-1.3.5-py3-none-any.whl", hash = "sha256:260f1dbc3a519453a9c856dedfe4beb4e50bd5a26d96386cb6c80856556bb91a"}, - {file = "Mako-1.3.5.tar.gz", hash = "sha256:48dbc20568c1d276a2698b36d968fa76161bf127194907ea6fc594fa81f943bc"}, + {file = "Mako-1.3.6-py3-none-any.whl", hash = "sha256:a91198468092a2f1a0de86ca92690fb0cfc43ca90ee17e15d93662b4c04b241a"}, + {file = "mako-1.3.6.tar.gz", hash = "sha256:9ec3a1583713479fae654f83ed9fa8c9a4c16b7bb0daba0e6bbebff50c0d983d"}, ] [package.dependencies] @@ -1654,71 +1572,72 @@ testing = ["coverage", "pytest", "pytest-cov", "pytest-regressions"] [[package]] name = "markupsafe" -version = "2.1.5" +version = "3.0.2" description = "Safely add untrusted strings to HTML/XML markup." optional = false -python-versions = ">=3.7" +python-versions = ">=3.9" files = [ - {file = "MarkupSafe-2.1.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a17a92de5231666cfbe003f0e4b9b3a7ae3afb1ec2845aadc2bacc93ff85febc"}, - {file = "MarkupSafe-2.1.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:72b6be590cc35924b02c78ef34b467da4ba07e4e0f0454a2c5907f473fc50ce5"}, - {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e61659ba32cf2cf1481e575d0462554625196a1f2fc06a1c777d3f48e8865d46"}, - {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2174c595a0d73a3080ca3257b40096db99799265e1c27cc5a610743acd86d62f"}, - {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ae2ad8ae6ebee9d2d94b17fb62763125f3f374c25618198f40cbb8b525411900"}, - {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:075202fa5b72c86ad32dc7d0b56024ebdbcf2048c0ba09f1cde31bfdd57bcfff"}, - {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:598e3276b64aff0e7b3451b72e94fa3c238d452e7ddcd893c3ab324717456bad"}, - {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fce659a462a1be54d2ffcacea5e3ba2d74daa74f30f5f143fe0c58636e355fdd"}, - {file = "MarkupSafe-2.1.5-cp310-cp310-win32.whl", hash = "sha256:d9fad5155d72433c921b782e58892377c44bd6252b5af2f67f16b194987338a4"}, - {file = "MarkupSafe-2.1.5-cp310-cp310-win_amd64.whl", hash = "sha256:bf50cd79a75d181c9181df03572cdce0fbb75cc353bc350712073108cba98de5"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:629ddd2ca402ae6dbedfceeba9c46d5f7b2a61d9749597d4307f943ef198fc1f"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5b7b716f97b52c5a14bffdf688f971b2d5ef4029127f1ad7a513973cfd818df2"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6ec585f69cec0aa07d945b20805be741395e28ac1627333b1c5b0105962ffced"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b91c037585eba9095565a3556f611e3cbfaa42ca1e865f7b8015fe5c7336d5a5"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7502934a33b54030eaf1194c21c692a534196063db72176b0c4028e140f8f32c"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:0e397ac966fdf721b2c528cf028494e86172b4feba51d65f81ffd65c63798f3f"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:c061bb86a71b42465156a3ee7bd58c8c2ceacdbeb95d05a99893e08b8467359a"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:3a57fdd7ce31c7ff06cdfbf31dafa96cc533c21e443d57f5b1ecc6cdc668ec7f"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-win32.whl", hash = "sha256:397081c1a0bfb5124355710fe79478cdbeb39626492b15d399526ae53422b906"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-win_amd64.whl", hash = "sha256:2b7c57a4dfc4f16f7142221afe5ba4e093e09e728ca65c51f5620c9aaeb9a617"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:8dec4936e9c3100156f8a2dc89c4b88d5c435175ff03413b443469c7c8c5f4d1"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:3c6b973f22eb18a789b1460b4b91bf04ae3f0c4234a0a6aa6b0a92f6f7b951d4"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ac07bad82163452a6884fe8fa0963fb98c2346ba78d779ec06bd7a6262132aee"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f5dfb42c4604dddc8e4305050aa6deb084540643ed5804d7455b5df8fe16f5e5"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ea3d8a3d18833cf4304cd2fc9cbb1efe188ca9b5efef2bdac7adc20594a0e46b"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:d050b3361367a06d752db6ead6e7edeb0009be66bc3bae0ee9d97fb326badc2a"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:bec0a414d016ac1a18862a519e54b2fd0fc8bbfd6890376898a6c0891dd82e9f"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:58c98fee265677f63a4385256a6d7683ab1832f3ddd1e66fe948d5880c21a169"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-win32.whl", hash = "sha256:8590b4ae07a35970728874632fed7bd57b26b0102df2d2b233b6d9d82f6c62ad"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-win_amd64.whl", hash = "sha256:823b65d8706e32ad2df51ed89496147a42a2a6e01c13cfb6ffb8b1e92bc910bb"}, - {file = "MarkupSafe-2.1.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:c8b29db45f8fe46ad280a7294f5c3ec36dbac9491f2d1c17345be8e69cc5928f"}, - {file = "MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ec6a563cff360b50eed26f13adc43e61bc0c04d94b8be985e6fb24b81f6dcfdf"}, - {file = "MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a549b9c31bec33820e885335b451286e2969a2d9e24879f83fe904a5ce59d70a"}, - {file = "MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4f11aa001c540f62c6166c7726f71f7573b52c68c31f014c25cc7901deea0b52"}, - {file = "MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:7b2e5a267c855eea6b4283940daa6e88a285f5f2a67f2220203786dfa59b37e9"}, - {file = "MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:2d2d793e36e230fd32babe143b04cec8a8b3eb8a3122d2aceb4a371e6b09b8df"}, - {file = "MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:ce409136744f6521e39fd8e2a24c53fa18ad67aa5bc7c2cf83645cce5b5c4e50"}, - {file = "MarkupSafe-2.1.5-cp37-cp37m-win32.whl", hash = "sha256:4096e9de5c6fdf43fb4f04c26fb114f61ef0bf2e5604b6ee3019d51b69e8c371"}, - {file = "MarkupSafe-2.1.5-cp37-cp37m-win_amd64.whl", hash = "sha256:4275d846e41ecefa46e2015117a9f491e57a71ddd59bbead77e904dc02b1bed2"}, - {file = "MarkupSafe-2.1.5-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:656f7526c69fac7f600bd1f400991cc282b417d17539a1b228617081106feb4a"}, - {file = "MarkupSafe-2.1.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:97cafb1f3cbcd3fd2b6fbfb99ae11cdb14deea0736fc2b0952ee177f2b813a46"}, - {file = "MarkupSafe-2.1.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f3fbcb7ef1f16e48246f704ab79d79da8a46891e2da03f8783a5b6fa41a9532"}, - {file = "MarkupSafe-2.1.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fa9db3f79de01457b03d4f01b34cf91bc0048eb2c3846ff26f66687c2f6d16ab"}, - {file = "MarkupSafe-2.1.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ffee1f21e5ef0d712f9033568f8344d5da8cc2869dbd08d87c84656e6a2d2f68"}, - {file = "MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:5dedb4db619ba5a2787a94d877bc8ffc0566f92a01c0ef214865e54ecc9ee5e0"}, - {file = "MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:30b600cf0a7ac9234b2638fbc0fb6158ba5bdcdf46aeb631ead21248b9affbc4"}, - {file = "MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:8dd717634f5a044f860435c1d8c16a270ddf0ef8588d4887037c5028b859b0c3"}, - {file = "MarkupSafe-2.1.5-cp38-cp38-win32.whl", hash = "sha256:daa4ee5a243f0f20d528d939d06670a298dd39b1ad5f8a72a4275124a7819eff"}, - {file = "MarkupSafe-2.1.5-cp38-cp38-win_amd64.whl", hash = "sha256:619bc166c4f2de5caa5a633b8b7326fbe98e0ccbfacabd87268a2b15ff73a029"}, - {file = "MarkupSafe-2.1.5-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:7a68b554d356a91cce1236aa7682dc01df0edba8d043fd1ce607c49dd3c1edcf"}, - {file = "MarkupSafe-2.1.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:db0b55e0f3cc0be60c1f19efdde9a637c32740486004f20d1cff53c3c0ece4d2"}, - {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3e53af139f8579a6d5f7b76549125f0d94d7e630761a2111bc431fd820e163b8"}, - {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:17b950fccb810b3293638215058e432159d2b71005c74371d784862b7e4683f3"}, - {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4c31f53cdae6ecfa91a77820e8b151dba54ab528ba65dfd235c80b086d68a465"}, - {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:bff1b4290a66b490a2f4719358c0cdcd9bafb6b8f061e45c7a2460866bf50c2e"}, - {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:bc1667f8b83f48511b94671e0e441401371dfd0f0a795c7daa4a3cd1dde55bea"}, - {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5049256f536511ee3f7e1b3f87d1d1209d327e818e6ae1365e8653d7e3abb6a6"}, - {file = "MarkupSafe-2.1.5-cp39-cp39-win32.whl", hash = "sha256:00e046b6dd71aa03a41079792f8473dc494d564611a8f89bbbd7cb93295ebdcf"}, - {file = "MarkupSafe-2.1.5-cp39-cp39-win_amd64.whl", hash = "sha256:fa173ec60341d6bb97a89f5ea19c85c5643c1e7dedebc22f5181eb73573142c5"}, - {file = "MarkupSafe-2.1.5.tar.gz", hash = "sha256:d283d37a890ba4c1ae73ffadf8046435c76e7bc2247bbb63c00bd1a709c6544b"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7e94c425039cde14257288fd61dcfb01963e658efbc0ff54f5306b06054700f8"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9e2d922824181480953426608b81967de705c3cef4d1af983af849d7bd619158"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:38a9ef736c01fccdd6600705b09dc574584b89bea478200c5fbf112a6b0d5579"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bbcb445fa71794da8f178f0f6d66789a28d7319071af7a496d4d507ed566270d"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:57cb5a3cf367aeb1d316576250f65edec5bb3be939e9247ae594b4bcbc317dfb"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:3809ede931876f5b2ec92eef964286840ed3540dadf803dd570c3b7e13141a3b"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e07c3764494e3776c602c1e78e298937c3315ccc9043ead7e685b7f2b8d47b3c"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:b424c77b206d63d500bcb69fa55ed8d0e6a3774056bdc4839fc9298a7edca171"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-win32.whl", hash = "sha256:fcabf5ff6eea076f859677f5f0b6b5c1a51e70a376b0579e0eadef8db48c6b50"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:6af100e168aa82a50e186c82875a5893c5597a0c1ccdb0d8b40240b1f28b969a"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:9025b4018f3a1314059769c7bf15441064b2207cb3f065e6ea1e7359cb46db9d"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:93335ca3812df2f366e80509ae119189886b0f3c2b81325d39efdb84a1e2ae93"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2cb8438c3cbb25e220c2ab33bb226559e7afb3baec11c4f218ffa7308603c832"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a123e330ef0853c6e822384873bef7507557d8e4a082961e1defa947aa59ba84"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1e084f686b92e5b83186b07e8a17fc09e38fff551f3602b249881fec658d3eca"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d8213e09c917a951de9d09ecee036d5c7d36cb6cb7dbaece4c71a60d79fb9798"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:5b02fb34468b6aaa40dfc198d813a641e3a63b98c2b05a16b9f80b7ec314185e"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:0bff5e0ae4ef2e1ae4fdf2dfd5b76c75e5c2fa4132d05fc1b0dabcd20c7e28c4"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-win32.whl", hash = "sha256:6c89876f41da747c8d3677a2b540fb32ef5715f97b66eeb0c6b66f5e3ef6f59d"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:70a87b411535ccad5ef2f1df5136506a10775d267e197e4cf531ced10537bd6b"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:9778bd8ab0a994ebf6f84c2b949e65736d5575320a17ae8984a77fab08db94cf"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:846ade7b71e3536c4e56b386c2a47adf5741d2d8b94ec9dc3e92e5e1ee1e2225"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1c99d261bd2d5f6b59325c92c73df481e05e57f19837bdca8413b9eac4bd8028"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e17c96c14e19278594aa4841ec148115f9c7615a47382ecb6b82bd8fea3ab0c8"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:88416bd1e65dcea10bc7569faacb2c20ce071dd1f87539ca2ab364bf6231393c"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2181e67807fc2fa785d0592dc2d6206c019b9502410671cc905d132a92866557"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:52305740fe773d09cffb16f8ed0427942901f00adedac82ec8b67752f58a1b22"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ad10d3ded218f1039f11a75f8091880239651b52e9bb592ca27de44eed242a48"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-win32.whl", hash = "sha256:0f4ca02bea9a23221c0182836703cbf8930c5e9454bacce27e767509fa286a30"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:8e06879fc22a25ca47312fbe7c8264eb0b662f6db27cb2d3bbbc74b1df4b9b87"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ba9527cdd4c926ed0760bc301f6728ef34d841f405abf9d4f959c478421e4efd"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f8b3d067f2e40fe93e1ccdd6b2e1d16c43140e76f02fb1319a05cf2b79d99430"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:569511d3b58c8791ab4c2e1285575265991e6d8f8700c7be0e88f86cb0672094"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:15ab75ef81add55874e7ab7055e9c397312385bd9ced94920f2802310c930396"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f3818cb119498c0678015754eba762e0d61e5b52d34c8b13d770f0719f7b1d79"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:cdb82a876c47801bb54a690c5ae105a46b392ac6099881cdfb9f6e95e4014c6a"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:cabc348d87e913db6ab4aa100f01b08f481097838bdddf7c7a84b7575b7309ca"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:444dcda765c8a838eaae23112db52f1efaf750daddb2d9ca300bcae1039adc5c"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-win32.whl", hash = "sha256:bcf3e58998965654fdaff38e58584d8937aa3096ab5354d493c77d1fdd66d7a1"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:e6a2a455bd412959b57a172ce6328d2dd1f01cb2135efda2e4576e8a23fa3b0f"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:b5a6b3ada725cea8a5e634536b1b01c30bcdcd7f9c6fff4151548d5bf6b3a36c"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:a904af0a6162c73e3edcb969eeeb53a63ceeb5d8cf642fade7d39e7963a22ddb"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4aa4e5faecf353ed117801a068ebab7b7e09ffb6e1d5e412dc852e0da018126c"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0ef13eaeee5b615fb07c9a7dadb38eac06a0608b41570d8ade51c56539e509d"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d16a81a06776313e817c951135cf7340a3e91e8c1ff2fac444cfd75fffa04afe"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:6381026f158fdb7c72a168278597a5e3a5222e83ea18f543112b2662a9b699c5"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:3d79d162e7be8f996986c064d1c7c817f6df3a77fe3d6859f6f9e7be4b8c213a"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:131a3c7689c85f5ad20f9f6fb1b866f402c445b220c19fe4308c0b147ccd2ad9"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-win32.whl", hash = "sha256:ba8062ed2cf21c07a9e295d5b8a2a5ce678b913b45fdf68c32d95d6c1291e0b6"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-win_amd64.whl", hash = "sha256:e444a31f8db13eb18ada366ab3cf45fd4b31e4db1236a4448f68778c1d1a5a2f"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:eaa0a10b7f72326f1372a713e73c3f739b524b3af41feb43e4921cb529f5929a"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:48032821bbdf20f5799ff537c7ac3d1fba0ba032cfc06194faffa8cda8b560ff"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1a9d3f5f0901fdec14d8d2f66ef7d035f2157240a433441719ac9a3fba440b13"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:88b49a3b9ff31e19998750c38e030fc7bb937398b1f78cfa599aaef92d693144"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cfad01eed2c2e0c01fd0ecd2ef42c492f7f93902e39a42fc9ee1692961443a29"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:1225beacc926f536dc82e45f8a4d68502949dc67eea90eab715dea3a21c1b5f0"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:3169b1eefae027567d1ce6ee7cae382c57fe26e82775f460f0b2778beaad66c0"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:eb7972a85c54febfb25b5c4b4f3af4dcc731994c7da0d8a0b4a6eb0640e1d178"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-win32.whl", hash = "sha256:8c4e8c3ce11e1f92f6536ff07154f9d49677ebaaafc32db9db4620bc11ed480f"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:6e296a513ca3d94054c2c881cc913116e90fd030ad1c656b3869762b754f5f8a"}, + {file = "markupsafe-3.0.2.tar.gz", hash = "sha256:ee55d3edf80167e48ea11a923c7386f4669df67d7994554387f84e7d8b0a2bf0"}, ] [[package]] @@ -1792,123 +1711,6 @@ files = [ {file = "mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba"}, ] -[[package]] -name = "msgpack" -version = "1.0.8" -description = "MessagePack serializer" -optional = false -python-versions = ">=3.8" -files = [ - {file = "msgpack-1.0.8-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:505fe3d03856ac7d215dbe005414bc28505d26f0c128906037e66d98c4e95868"}, - {file = "msgpack-1.0.8-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e6b7842518a63a9f17107eb176320960ec095a8ee3b4420b5f688e24bf50c53c"}, - {file = "msgpack-1.0.8-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:376081f471a2ef24828b83a641a02c575d6103a3ad7fd7dade5486cad10ea659"}, - {file = "msgpack-1.0.8-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5e390971d082dba073c05dbd56322427d3280b7cc8b53484c9377adfbae67dc2"}, - {file = "msgpack-1.0.8-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:00e073efcba9ea99db5acef3959efa45b52bc67b61b00823d2a1a6944bf45982"}, - {file = "msgpack-1.0.8-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:82d92c773fbc6942a7a8b520d22c11cfc8fd83bba86116bfcf962c2f5c2ecdaa"}, - {file = "msgpack-1.0.8-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:9ee32dcb8e531adae1f1ca568822e9b3a738369b3b686d1477cbc643c4a9c128"}, - {file = "msgpack-1.0.8-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:e3aa7e51d738e0ec0afbed661261513b38b3014754c9459508399baf14ae0c9d"}, - {file = "msgpack-1.0.8-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:69284049d07fce531c17404fcba2bb1df472bc2dcdac642ae71a2d079d950653"}, - {file = "msgpack-1.0.8-cp310-cp310-win32.whl", hash = "sha256:13577ec9e247f8741c84d06b9ece5f654920d8365a4b636ce0e44f15e07ec693"}, - {file = "msgpack-1.0.8-cp310-cp310-win_amd64.whl", hash = "sha256:e532dbd6ddfe13946de050d7474e3f5fb6ec774fbb1a188aaf469b08cf04189a"}, - {file = "msgpack-1.0.8-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:9517004e21664f2b5a5fd6333b0731b9cf0817403a941b393d89a2f1dc2bd836"}, - {file = "msgpack-1.0.8-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:d16a786905034e7e34098634b184a7d81f91d4c3d246edc6bd7aefb2fd8ea6ad"}, - {file = "msgpack-1.0.8-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e2872993e209f7ed04d963e4b4fbae72d034844ec66bc4ca403329db2074377b"}, - {file = "msgpack-1.0.8-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5c330eace3dd100bdb54b5653b966de7f51c26ec4a7d4e87132d9b4f738220ba"}, - {file = "msgpack-1.0.8-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:83b5c044f3eff2a6534768ccfd50425939e7a8b5cf9a7261c385de1e20dcfc85"}, - {file = "msgpack-1.0.8-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1876b0b653a808fcd50123b953af170c535027bf1d053b59790eebb0aeb38950"}, - {file = "msgpack-1.0.8-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:dfe1f0f0ed5785c187144c46a292b8c34c1295c01da12e10ccddfc16def4448a"}, - {file = "msgpack-1.0.8-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:3528807cbbb7f315bb81959d5961855e7ba52aa60a3097151cb21956fbc7502b"}, - {file = "msgpack-1.0.8-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e2f879ab92ce502a1e65fce390eab619774dda6a6ff719718069ac94084098ce"}, - {file = "msgpack-1.0.8-cp311-cp311-win32.whl", hash = "sha256:26ee97a8261e6e35885c2ecd2fd4a6d38252246f94a2aec23665a4e66d066305"}, - {file = "msgpack-1.0.8-cp311-cp311-win_amd64.whl", hash = "sha256:eadb9f826c138e6cf3c49d6f8de88225a3c0ab181a9b4ba792e006e5292d150e"}, - {file = "msgpack-1.0.8-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:114be227f5213ef8b215c22dde19532f5da9652e56e8ce969bf0a26d7c419fee"}, - {file = "msgpack-1.0.8-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:d661dc4785affa9d0edfdd1e59ec056a58b3dbb9f196fa43587f3ddac654ac7b"}, - {file = "msgpack-1.0.8-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:d56fd9f1f1cdc8227d7b7918f55091349741904d9520c65f0139a9755952c9e8"}, - {file = "msgpack-1.0.8-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0726c282d188e204281ebd8de31724b7d749adebc086873a59efb8cf7ae27df3"}, - {file = "msgpack-1.0.8-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8db8e423192303ed77cff4dce3a4b88dbfaf43979d280181558af5e2c3c71afc"}, - {file = "msgpack-1.0.8-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:99881222f4a8c2f641f25703963a5cefb076adffd959e0558dc9f803a52d6a58"}, - {file = "msgpack-1.0.8-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:b5505774ea2a73a86ea176e8a9a4a7c8bf5d521050f0f6f8426afe798689243f"}, - {file = "msgpack-1.0.8-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:ef254a06bcea461e65ff0373d8a0dd1ed3aa004af48839f002a0c994a6f72d04"}, - {file = "msgpack-1.0.8-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:e1dd7839443592d00e96db831eddb4111a2a81a46b028f0facd60a09ebbdd543"}, - {file = "msgpack-1.0.8-cp312-cp312-win32.whl", hash = "sha256:64d0fcd436c5683fdd7c907eeae5e2cbb5eb872fafbc03a43609d7941840995c"}, - {file = "msgpack-1.0.8-cp312-cp312-win_amd64.whl", hash = "sha256:74398a4cf19de42e1498368c36eed45d9528f5fd0155241e82c4082b7e16cffd"}, - {file = "msgpack-1.0.8-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:0ceea77719d45c839fd73abcb190b8390412a890df2f83fb8cf49b2a4b5c2f40"}, - {file = "msgpack-1.0.8-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1ab0bbcd4d1f7b6991ee7c753655b481c50084294218de69365f8f1970d4c151"}, - {file = "msgpack-1.0.8-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:1cce488457370ffd1f953846f82323cb6b2ad2190987cd4d70b2713e17268d24"}, - {file = "msgpack-1.0.8-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3923a1778f7e5ef31865893fdca12a8d7dc03a44b33e2a5f3295416314c09f5d"}, - {file = "msgpack-1.0.8-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a22e47578b30a3e199ab067a4d43d790249b3c0587d9a771921f86250c8435db"}, - {file = "msgpack-1.0.8-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bd739c9251d01e0279ce729e37b39d49a08c0420d3fee7f2a4968c0576678f77"}, - {file = "msgpack-1.0.8-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:d3420522057ebab1728b21ad473aa950026d07cb09da41103f8e597dfbfaeb13"}, - {file = "msgpack-1.0.8-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:5845fdf5e5d5b78a49b826fcdc0eb2e2aa7191980e3d2cfd2a30303a74f212e2"}, - {file = "msgpack-1.0.8-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:6a0e76621f6e1f908ae52860bdcb58e1ca85231a9b0545e64509c931dd34275a"}, - {file = "msgpack-1.0.8-cp38-cp38-win32.whl", hash = "sha256:374a8e88ddab84b9ada695d255679fb99c53513c0a51778796fcf0944d6c789c"}, - {file = "msgpack-1.0.8-cp38-cp38-win_amd64.whl", hash = "sha256:f3709997b228685fe53e8c433e2df9f0cdb5f4542bd5114ed17ac3c0129b0480"}, - {file = "msgpack-1.0.8-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:f51bab98d52739c50c56658cc303f190785f9a2cd97b823357e7aeae54c8f68a"}, - {file = "msgpack-1.0.8-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:73ee792784d48aa338bba28063e19a27e8d989344f34aad14ea6e1b9bd83f596"}, - {file = "msgpack-1.0.8-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f9904e24646570539a8950400602d66d2b2c492b9010ea7e965025cb71d0c86d"}, - {file = "msgpack-1.0.8-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e75753aeda0ddc4c28dce4c32ba2f6ec30b1b02f6c0b14e547841ba5b24f753f"}, - {file = "msgpack-1.0.8-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5dbf059fb4b7c240c873c1245ee112505be27497e90f7c6591261c7d3c3a8228"}, - {file = "msgpack-1.0.8-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4916727e31c28be8beaf11cf117d6f6f188dcc36daae4e851fee88646f5b6b18"}, - {file = "msgpack-1.0.8-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:7938111ed1358f536daf311be244f34df7bf3cdedb3ed883787aca97778b28d8"}, - {file = "msgpack-1.0.8-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:493c5c5e44b06d6c9268ce21b302c9ca055c1fd3484c25ba41d34476c76ee746"}, - {file = "msgpack-1.0.8-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5fbb160554e319f7b22ecf530a80a3ff496d38e8e07ae763b9e82fadfe96f273"}, - {file = "msgpack-1.0.8-cp39-cp39-win32.whl", hash = "sha256:f9af38a89b6a5c04b7d18c492c8ccf2aee7048aff1ce8437c4683bb5a1df893d"}, - {file = "msgpack-1.0.8-cp39-cp39-win_amd64.whl", hash = "sha256:ed59dd52075f8fc91da6053b12e8c89e37aa043f8986efd89e61fae69dc1b011"}, - {file = "msgpack-1.0.8.tar.gz", hash = "sha256:95c02b0e27e706e48d0e5426d1710ca78e0f0628d6e89d5b5a5b91a5f12274f3"}, -] - -[[package]] -name = "msgspec" -version = "0.18.6" -description = "A fast serialization and validation library, with builtin support for JSON, MessagePack, YAML, and TOML." -optional = false -python-versions = ">=3.8" -files = [ - {file = "msgspec-0.18.6-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:77f30b0234eceeff0f651119b9821ce80949b4d667ad38f3bfed0d0ebf9d6d8f"}, - {file = "msgspec-0.18.6-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:1a76b60e501b3932782a9da039bd1cd552b7d8dec54ce38332b87136c64852dd"}, - {file = "msgspec-0.18.6-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:06acbd6edf175bee0e36295d6b0302c6de3aaf61246b46f9549ca0041a9d7177"}, - {file = "msgspec-0.18.6-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:40a4df891676d9c28a67c2cc39947c33de516335680d1316a89e8f7218660410"}, - {file = "msgspec-0.18.6-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:a6896f4cd5b4b7d688018805520769a8446df911eb93b421c6c68155cdf9dd5a"}, - {file = "msgspec-0.18.6-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:3ac4dd63fd5309dd42a8c8c36c1563531069152be7819518be0a9d03be9788e4"}, - {file = "msgspec-0.18.6-cp310-cp310-win_amd64.whl", hash = "sha256:fda4c357145cf0b760000c4ad597e19b53adf01382b711f281720a10a0fe72b7"}, - {file = "msgspec-0.18.6-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:e77e56ffe2701e83a96e35770c6adb655ffc074d530018d1b584a8e635b4f36f"}, - {file = "msgspec-0.18.6-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d5351afb216b743df4b6b147691523697ff3a2fc5f3d54f771e91219f5c23aaa"}, - {file = "msgspec-0.18.6-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c3232fabacef86fe8323cecbe99abbc5c02f7698e3f5f2e248e3480b66a3596b"}, - {file = "msgspec-0.18.6-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e3b524df6ea9998bbc99ea6ee4d0276a101bcc1aa8d14887bb823914d9f60d07"}, - {file = "msgspec-0.18.6-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:37f67c1d81272131895bb20d388dd8d341390acd0e192a55ab02d4d6468b434c"}, - {file = "msgspec-0.18.6-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:d0feb7a03d971c1c0353de1a8fe30bb6579c2dc5ccf29b5f7c7ab01172010492"}, - {file = "msgspec-0.18.6-cp311-cp311-win_amd64.whl", hash = "sha256:41cf758d3f40428c235c0f27bc6f322d43063bc32da7b9643e3f805c21ed57b4"}, - {file = "msgspec-0.18.6-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:d86f5071fe33e19500920333c11e2267a31942d18fed4d9de5bc2fbab267d28c"}, - {file = "msgspec-0.18.6-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ce13981bfa06f5eb126a3a5a38b1976bddb49a36e4f46d8e6edecf33ccf11df1"}, - {file = "msgspec-0.18.6-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e97dec6932ad5e3ee1e3c14718638ba333befc45e0661caa57033cd4cc489466"}, - {file = "msgspec-0.18.6-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ad237100393f637b297926cae1868b0d500f764ccd2f0623a380e2bcfb2809ca"}, - {file = "msgspec-0.18.6-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:db1d8626748fa5d29bbd15da58b2d73af25b10aa98abf85aab8028119188ed57"}, - {file = "msgspec-0.18.6-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:d70cb3d00d9f4de14d0b31d38dfe60c88ae16f3182988246a9861259c6722af6"}, - {file = "msgspec-0.18.6-cp312-cp312-win_amd64.whl", hash = "sha256:1003c20bfe9c6114cc16ea5db9c5466e49fae3d7f5e2e59cb70693190ad34da0"}, - {file = "msgspec-0.18.6-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:f7d9faed6dfff654a9ca7d9b0068456517f63dbc3aa704a527f493b9200b210a"}, - {file = "msgspec-0.18.6-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:9da21f804c1a1471f26d32b5d9bc0480450ea77fbb8d9db431463ab64aaac2cf"}, - {file = "msgspec-0.18.6-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:46eb2f6b22b0e61c137e65795b97dc515860bf6ec761d8fb65fdb62aa094ba61"}, - {file = "msgspec-0.18.6-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c8355b55c80ac3e04885d72db515817d9fbb0def3bab936bba104e99ad22cf46"}, - {file = "msgspec-0.18.6-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:9080eb12b8f59e177bd1eb5c21e24dd2ba2fa88a1dbc9a98e05ad7779b54c681"}, - {file = "msgspec-0.18.6-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:cc001cf39becf8d2dcd3f413a4797c55009b3a3cdbf78a8bf5a7ca8fdb76032c"}, - {file = "msgspec-0.18.6-cp38-cp38-win_amd64.whl", hash = "sha256:fac5834e14ac4da1fca373753e0c4ec9c8069d1fe5f534fa5208453b6065d5be"}, - {file = "msgspec-0.18.6-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:974d3520fcc6b824a6dedbdf2b411df31a73e6e7414301abac62e6b8d03791b4"}, - {file = "msgspec-0.18.6-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:fd62e5818731a66aaa8e9b0a1e5543dc979a46278da01e85c3c9a1a4f047ef7e"}, - {file = "msgspec-0.18.6-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7481355a1adcf1f08dedd9311193c674ffb8bf7b79314b4314752b89a2cf7f1c"}, - {file = "msgspec-0.18.6-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6aa85198f8f154cf35d6f979998f6dadd3dc46a8a8c714632f53f5d65b315c07"}, - {file = "msgspec-0.18.6-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:0e24539b25c85c8f0597274f11061c102ad6b0c56af053373ba4629772b407be"}, - {file = "msgspec-0.18.6-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:c61ee4d3be03ea9cd089f7c8e36158786cd06e51fbb62529276452bbf2d52ece"}, - {file = "msgspec-0.18.6-cp39-cp39-win_amd64.whl", hash = "sha256:b5c390b0b0b7da879520d4ae26044d74aeee5144f83087eb7842ba59c02bc090"}, - {file = "msgspec-0.18.6.tar.gz", hash = "sha256:a59fc3b4fcdb972d09138cb516dbde600c99d07c38fd9372a6ef500d2d031b4e"}, -] - -[package.extras] -dev = ["attrs", "coverage", "furo", "gcovr", "ipython", "msgpack", "mypy", "pre-commit", "pyright", "pytest", "pyyaml", "sphinx", "sphinx-copybutton", "sphinx-design", "tomli", "tomli-w"] -doc = ["furo", "ipython", "sphinx", "sphinx-copybutton", "sphinx-design"] -test = ["attrs", "msgpack", "mypy", "pyright", "pytest", "pyyaml", "tomli", "tomli-w"] -toml = ["tomli", "tomli-w"] -yaml = ["pyyaml"] - [[package]] name = "msoffcrypto-tool" version = "5.4.2" @@ -1937,12 +1739,13 @@ files = [ [[package]] name = "nanobind" -version = "2.1.0" +version = "2.2.0" description = "nanobind: tiny and efficient C++/Python bindings" optional = false python-versions = "*" files = [ - {file = "nanobind-2.1.0-py3-none-any.whl", hash = "sha256:a613a2ce750fee63f03dc8a36593be2bdc2929cb4cea56b38fafeb74b85c3a5f"}, + {file = "nanobind-2.2.0-py3-none-any.whl", hash = "sha256:138685ec9c5de4f57dd02d715b89ffcbcabae39c4e36b8b2c40eea2f1aa2f0d7"}, + {file = "nanobind-2.2.0.tar.gz", hash = "sha256:53fa7a6227bddecaa4a0710e0b8dc18fad4c8ded7a0a31d6eddcf68009ead603"}, ] [[package]] @@ -1955,24 +1758,6 @@ files = [ {file = "netstruct-1.1.2.zip", hash = "sha256:70b6a5c73f5bbc7ab57b019369642adfb34dd8af41b948c400ce95f952b7df9a"}, ] -[[package]] -name = "networkx" -version = "3.1" -description = "Python package for creating and manipulating graphs and networks" -optional = false -python-versions = ">=3.8" -files = [ - {file = "networkx-3.1-py3-none-any.whl", hash = "sha256:4f33f68cb2afcf86f28a45f43efc27a9386b535d567d2127f8f61d51dec58d36"}, - {file = "networkx-3.1.tar.gz", hash = "sha256:de346335408f84de0eada6ff9fafafff9bcda11f0a0dfaa931133debb146ab61"}, -] - -[package.extras] -default = ["matplotlib (>=3.4)", "numpy (>=1.20)", "pandas (>=1.3)", "scipy (>=1.8)"] -developer = ["mypy (>=1.1)", "pre-commit (>=3.2)"] -doc = ["nb2plots (>=0.6)", "numpydoc (>=1.5)", "pillow (>=9.4)", "pydata-sphinx-theme (>=0.13)", "sphinx (>=6.1)", "sphinx-gallery (>=0.12)", "texext (>=0.6.7)"] -extra = ["lxml (>=4.6)", "pydot (>=1.4.2)", "pygraphviz (>=1.10)", "sympy (>=1.10)"] -test = ["codecov (>=2.1)", "pytest (>=7.2)", "pytest-cov (>=4.0)"] - [[package]] name = "nodeenv" version = "1.9.1" @@ -2173,95 +1958,90 @@ files = [ [[package]] name = "pillow" -version = "10.4.0" +version = "11.0.0" description = "Python Imaging Library (Fork)" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "pillow-10.4.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:4d9667937cfa347525b319ae34375c37b9ee6b525440f3ef48542fcf66f2731e"}, - {file = "pillow-10.4.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:543f3dc61c18dafb755773efc89aae60d06b6596a63914107f75459cf984164d"}, - {file = "pillow-10.4.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7928ecbf1ece13956b95d9cbcfc77137652b02763ba384d9ab508099a2eca856"}, - {file = "pillow-10.4.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e4d49b85c4348ea0b31ea63bc75a9f3857869174e2bf17e7aba02945cd218e6f"}, - {file = "pillow-10.4.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:6c762a5b0997f5659a5ef2266abc1d8851ad7749ad9a6a5506eb23d314e4f46b"}, - {file = "pillow-10.4.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:a985e028fc183bf12a77a8bbf36318db4238a3ded7fa9df1b9a133f1cb79f8fc"}, - {file = "pillow-10.4.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:812f7342b0eee081eaec84d91423d1b4650bb9828eb53d8511bcef8ce5aecf1e"}, - {file = "pillow-10.4.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:ac1452d2fbe4978c2eec89fb5a23b8387aba707ac72810d9490118817d9c0b46"}, - {file = "pillow-10.4.0-cp310-cp310-win32.whl", hash = "sha256:bcd5e41a859bf2e84fdc42f4edb7d9aba0a13d29a2abadccafad99de3feff984"}, - {file = "pillow-10.4.0-cp310-cp310-win_amd64.whl", hash = "sha256:ecd85a8d3e79cd7158dec1c9e5808e821feea088e2f69a974db5edf84dc53141"}, - {file = "pillow-10.4.0-cp310-cp310-win_arm64.whl", hash = "sha256:ff337c552345e95702c5fde3158acb0625111017d0e5f24bf3acdb9cc16b90d1"}, - {file = "pillow-10.4.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:0a9ec697746f268507404647e531e92889890a087e03681a3606d9b920fbee3c"}, - {file = "pillow-10.4.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:dfe91cb65544a1321e631e696759491ae04a2ea11d36715eca01ce07284738be"}, - {file = "pillow-10.4.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5dc6761a6efc781e6a1544206f22c80c3af4c8cf461206d46a1e6006e4429ff3"}, - {file = "pillow-10.4.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5e84b6cc6a4a3d76c153a6b19270b3526a5a8ed6b09501d3af891daa2a9de7d6"}, - {file = "pillow-10.4.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:bbc527b519bd3aa9d7f429d152fea69f9ad37c95f0b02aebddff592688998abe"}, - {file = "pillow-10.4.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:76a911dfe51a36041f2e756b00f96ed84677cdeb75d25c767f296c1c1eda1319"}, - {file = "pillow-10.4.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:59291fb29317122398786c2d44427bbd1a6d7ff54017075b22be9d21aa59bd8d"}, - {file = "pillow-10.4.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:416d3a5d0e8cfe4f27f574362435bc9bae57f679a7158e0096ad2beb427b8696"}, - {file = "pillow-10.4.0-cp311-cp311-win32.whl", hash = "sha256:7086cc1d5eebb91ad24ded9f58bec6c688e9f0ed7eb3dbbf1e4800280a896496"}, - {file = "pillow-10.4.0-cp311-cp311-win_amd64.whl", hash = "sha256:cbed61494057c0f83b83eb3a310f0bf774b09513307c434d4366ed64f4128a91"}, - {file = "pillow-10.4.0-cp311-cp311-win_arm64.whl", hash = "sha256:f5f0c3e969c8f12dd2bb7e0b15d5c468b51e5017e01e2e867335c81903046a22"}, - {file = "pillow-10.4.0-cp312-cp312-macosx_10_10_x86_64.whl", hash = "sha256:673655af3eadf4df6b5457033f086e90299fdd7a47983a13827acf7459c15d94"}, - {file = "pillow-10.4.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:866b6942a92f56300012f5fbac71f2d610312ee65e22f1aa2609e491284e5597"}, - {file = "pillow-10.4.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:29dbdc4207642ea6aad70fbde1a9338753d33fb23ed6956e706936706f52dd80"}, - {file = "pillow-10.4.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bf2342ac639c4cf38799a44950bbc2dfcb685f052b9e262f446482afaf4bffca"}, - {file = "pillow-10.4.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:f5b92f4d70791b4a67157321c4e8225d60b119c5cc9aee8ecf153aace4aad4ef"}, - {file = "pillow-10.4.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:86dcb5a1eb778d8b25659d5e4341269e8590ad6b4e8b44d9f4b07f8d136c414a"}, - {file = "pillow-10.4.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:780c072c2e11c9b2c7ca37f9a2ee8ba66f44367ac3e5c7832afcfe5104fd6d1b"}, - {file = "pillow-10.4.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:37fb69d905be665f68f28a8bba3c6d3223c8efe1edf14cc4cfa06c241f8c81d9"}, - {file = "pillow-10.4.0-cp312-cp312-win32.whl", hash = "sha256:7dfecdbad5c301d7b5bde160150b4db4c659cee2b69589705b6f8a0c509d9f42"}, - {file = "pillow-10.4.0-cp312-cp312-win_amd64.whl", hash = "sha256:1d846aea995ad352d4bdcc847535bd56e0fd88d36829d2c90be880ef1ee4668a"}, - {file = "pillow-10.4.0-cp312-cp312-win_arm64.whl", hash = "sha256:e553cad5179a66ba15bb18b353a19020e73a7921296a7979c4a2b7f6a5cd57f9"}, - {file = "pillow-10.4.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:8bc1a764ed8c957a2e9cacf97c8b2b053b70307cf2996aafd70e91a082e70df3"}, - {file = "pillow-10.4.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:6209bb41dc692ddfee4942517c19ee81b86c864b626dbfca272ec0f7cff5d9fb"}, - {file = "pillow-10.4.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bee197b30783295d2eb680b311af15a20a8b24024a19c3a26431ff83eb8d1f70"}, - {file = "pillow-10.4.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1ef61f5dd14c300786318482456481463b9d6b91ebe5ef12f405afbba77ed0be"}, - {file = "pillow-10.4.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:297e388da6e248c98bc4a02e018966af0c5f92dfacf5a5ca22fa01cb3179bca0"}, - {file = "pillow-10.4.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:e4db64794ccdf6cb83a59d73405f63adbe2a1887012e308828596100a0b2f6cc"}, - {file = "pillow-10.4.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:bd2880a07482090a3bcb01f4265f1936a903d70bc740bfcb1fd4e8a2ffe5cf5a"}, - {file = "pillow-10.4.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4b35b21b819ac1dbd1233317adeecd63495f6babf21b7b2512d244ff6c6ce309"}, - {file = "pillow-10.4.0-cp313-cp313-win32.whl", hash = "sha256:551d3fd6e9dc15e4c1eb6fc4ba2b39c0c7933fa113b220057a34f4bb3268a060"}, - {file = "pillow-10.4.0-cp313-cp313-win_amd64.whl", hash = "sha256:030abdbe43ee02e0de642aee345efa443740aa4d828bfe8e2eb11922ea6a21ea"}, - {file = "pillow-10.4.0-cp313-cp313-win_arm64.whl", hash = "sha256:5b001114dd152cfd6b23befeb28d7aee43553e2402c9f159807bf55f33af8a8d"}, - {file = "pillow-10.4.0-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:8d4d5063501b6dd4024b8ac2f04962d661222d120381272deea52e3fc52d3736"}, - {file = "pillow-10.4.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:7c1ee6f42250df403c5f103cbd2768a28fe1a0ea1f0f03fe151c8741e1469c8b"}, - {file = "pillow-10.4.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b15e02e9bb4c21e39876698abf233c8c579127986f8207200bc8a8f6bb27acf2"}, - {file = "pillow-10.4.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7a8d4bade9952ea9a77d0c3e49cbd8b2890a399422258a77f357b9cc9be8d680"}, - {file = "pillow-10.4.0-cp38-cp38-manylinux_2_28_aarch64.whl", hash = "sha256:43efea75eb06b95d1631cb784aa40156177bf9dd5b4b03ff38979e048258bc6b"}, - {file = "pillow-10.4.0-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:950be4d8ba92aca4b2bb0741285a46bfae3ca699ef913ec8416c1b78eadd64cd"}, - {file = "pillow-10.4.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:d7480af14364494365e89d6fddc510a13e5a2c3584cb19ef65415ca57252fb84"}, - {file = "pillow-10.4.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:73664fe514b34c8f02452ffb73b7a92c6774e39a647087f83d67f010eb9a0cf0"}, - {file = "pillow-10.4.0-cp38-cp38-win32.whl", hash = "sha256:e88d5e6ad0d026fba7bdab8c3f225a69f063f116462c49892b0149e21b6c0a0e"}, - {file = "pillow-10.4.0-cp38-cp38-win_amd64.whl", hash = "sha256:5161eef006d335e46895297f642341111945e2c1c899eb406882a6c61a4357ab"}, - {file = "pillow-10.4.0-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:0ae24a547e8b711ccaaf99c9ae3cd975470e1a30caa80a6aaee9a2f19c05701d"}, - {file = "pillow-10.4.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:298478fe4f77a4408895605f3482b6cc6222c018b2ce565c2b6b9c354ac3229b"}, - {file = "pillow-10.4.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:134ace6dc392116566980ee7436477d844520a26a4b1bd4053f6f47d096997fd"}, - {file = "pillow-10.4.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:930044bb7679ab003b14023138b50181899da3f25de50e9dbee23b61b4de2126"}, - {file = "pillow-10.4.0-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:c76e5786951e72ed3686e122d14c5d7012f16c8303a674d18cdcd6d89557fc5b"}, - {file = "pillow-10.4.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:b2724fdb354a868ddf9a880cb84d102da914e99119211ef7ecbdc613b8c96b3c"}, - {file = "pillow-10.4.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:dbc6ae66518ab3c5847659e9988c3b60dc94ffb48ef9168656e0019a93dbf8a1"}, - {file = "pillow-10.4.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:06b2f7898047ae93fad74467ec3d28fe84f7831370e3c258afa533f81ef7f3df"}, - {file = "pillow-10.4.0-cp39-cp39-win32.whl", hash = "sha256:7970285ab628a3779aecc35823296a7869f889b8329c16ad5a71e4901a3dc4ef"}, - {file = "pillow-10.4.0-cp39-cp39-win_amd64.whl", hash = "sha256:961a7293b2457b405967af9c77dcaa43cc1a8cd50d23c532e62d48ab6cdd56f5"}, - {file = "pillow-10.4.0-cp39-cp39-win_arm64.whl", hash = "sha256:32cda9e3d601a52baccb2856b8ea1fc213c90b340c542dcef77140dfa3278a9e"}, - {file = "pillow-10.4.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:5b4815f2e65b30f5fbae9dfffa8636d992d49705723fe86a3661806e069352d4"}, - {file = "pillow-10.4.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:8f0aef4ef59694b12cadee839e2ba6afeab89c0f39a3adc02ed51d109117b8da"}, - {file = "pillow-10.4.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9f4727572e2918acaa9077c919cbbeb73bd2b3ebcfe033b72f858fc9fbef0026"}, - {file = "pillow-10.4.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ff25afb18123cea58a591ea0244b92eb1e61a1fd497bf6d6384f09bc3262ec3e"}, - {file = "pillow-10.4.0-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:dc3e2db6ba09ffd7d02ae9141cfa0ae23393ee7687248d46a7507b75d610f4f5"}, - {file = "pillow-10.4.0-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:02a2be69f9c9b8c1e97cf2713e789d4e398c751ecfd9967c18d0ce304efbf885"}, - {file = "pillow-10.4.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:0755ffd4a0c6f267cccbae2e9903d95477ca2f77c4fcf3a3a09570001856c8a5"}, - {file = "pillow-10.4.0-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:a02364621fe369e06200d4a16558e056fe2805d3468350df3aef21e00d26214b"}, - {file = "pillow-10.4.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:1b5dea9831a90e9d0721ec417a80d4cbd7022093ac38a568db2dd78363b00908"}, - {file = "pillow-10.4.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9b885f89040bb8c4a1573566bbb2f44f5c505ef6e74cec7ab9068c900047f04b"}, - {file = "pillow-10.4.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:87dd88ded2e6d74d31e1e0a99a726a6765cda32d00ba72dc37f0651f306daaa8"}, - {file = "pillow-10.4.0-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:2db98790afc70118bd0255c2eeb465e9767ecf1f3c25f9a1abb8ffc8cfd1fe0a"}, - {file = "pillow-10.4.0-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:f7baece4ce06bade126fb84b8af1c33439a76d8a6fd818970215e0560ca28c27"}, - {file = "pillow-10.4.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:cfdd747216947628af7b259d274771d84db2268ca062dd5faf373639d00113a3"}, - {file = "pillow-10.4.0.tar.gz", hash = "sha256:166c1cd4d24309b30d61f79f4a9114b7b2313d7450912277855ff5dfd7cd4a06"}, + {file = "pillow-11.0.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:6619654954dc4936fcff82db8eb6401d3159ec6be81e33c6000dfd76ae189947"}, + {file = "pillow-11.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:b3c5ac4bed7519088103d9450a1107f76308ecf91d6dabc8a33a2fcfb18d0fba"}, + {file = "pillow-11.0.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a65149d8ada1055029fcb665452b2814fe7d7082fcb0c5bed6db851cb69b2086"}, + {file = "pillow-11.0.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:88a58d8ac0cc0e7f3a014509f0455248a76629ca9b604eca7dc5927cc593c5e9"}, + {file = "pillow-11.0.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:c26845094b1af3c91852745ae78e3ea47abf3dbcd1cf962f16b9a5fbe3ee8488"}, + {file = "pillow-11.0.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:1a61b54f87ab5786b8479f81c4b11f4d61702830354520837f8cc791ebba0f5f"}, + {file = "pillow-11.0.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:674629ff60030d144b7bca2b8330225a9b11c482ed408813924619c6f302fdbb"}, + {file = "pillow-11.0.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:598b4e238f13276e0008299bd2482003f48158e2b11826862b1eb2ad7c768b97"}, + {file = "pillow-11.0.0-cp310-cp310-win32.whl", hash = "sha256:9a0f748eaa434a41fccf8e1ee7a3eed68af1b690e75328fd7a60af123c193b50"}, + {file = "pillow-11.0.0-cp310-cp310-win_amd64.whl", hash = "sha256:a5629742881bcbc1f42e840af185fd4d83a5edeb96475a575f4da50d6ede337c"}, + {file = "pillow-11.0.0-cp310-cp310-win_arm64.whl", hash = "sha256:ee217c198f2e41f184f3869f3e485557296d505b5195c513b2bfe0062dc537f1"}, + {file = "pillow-11.0.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:1c1d72714f429a521d8d2d018badc42414c3077eb187a59579f28e4270b4b0fc"}, + {file = "pillow-11.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:499c3a1b0d6fc8213519e193796eb1a86a1be4b1877d678b30f83fd979811d1a"}, + {file = "pillow-11.0.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c8b2351c85d855293a299038e1f89db92a2f35e8d2f783489c6f0b2b5f3fe8a3"}, + {file = "pillow-11.0.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6f4dba50cfa56f910241eb7f883c20f1e7b1d8f7d91c750cd0b318bad443f4d5"}, + {file = "pillow-11.0.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:5ddbfd761ee00c12ee1be86c9c0683ecf5bb14c9772ddbd782085779a63dd55b"}, + {file = "pillow-11.0.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:45c566eb10b8967d71bf1ab8e4a525e5a93519e29ea071459ce517f6b903d7fa"}, + {file = "pillow-11.0.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:b4fd7bd29610a83a8c9b564d457cf5bd92b4e11e79a4ee4716a63c959699b306"}, + {file = "pillow-11.0.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:cb929ca942d0ec4fac404cbf520ee6cac37bf35be479b970c4ffadf2b6a1cad9"}, + {file = "pillow-11.0.0-cp311-cp311-win32.whl", hash = "sha256:006bcdd307cc47ba43e924099a038cbf9591062e6c50e570819743f5607404f5"}, + {file = "pillow-11.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:52a2d8323a465f84faaba5236567d212c3668f2ab53e1c74c15583cf507a0291"}, + {file = "pillow-11.0.0-cp311-cp311-win_arm64.whl", hash = "sha256:16095692a253047fe3ec028e951fa4221a1f3ed3d80c397e83541a3037ff67c9"}, + {file = "pillow-11.0.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d2c0a187a92a1cb5ef2c8ed5412dd8d4334272617f532d4ad4de31e0495bd923"}, + {file = "pillow-11.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:084a07ef0821cfe4858fe86652fffac8e187b6ae677e9906e192aafcc1b69903"}, + {file = "pillow-11.0.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8069c5179902dcdce0be9bfc8235347fdbac249d23bd90514b7a47a72d9fecf4"}, + {file = "pillow-11.0.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f02541ef64077f22bf4924f225c0fd1248c168f86e4b7abdedd87d6ebaceab0f"}, + {file = "pillow-11.0.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:fcb4621042ac4b7865c179bb972ed0da0218a076dc1820ffc48b1d74c1e37fe9"}, + {file = "pillow-11.0.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:00177a63030d612148e659b55ba99527803288cea7c75fb05766ab7981a8c1b7"}, + {file = "pillow-11.0.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8853a3bf12afddfdf15f57c4b02d7ded92c7a75a5d7331d19f4f9572a89c17e6"}, + {file = "pillow-11.0.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3107c66e43bda25359d5ef446f59c497de2b5ed4c7fdba0894f8d6cf3822dafc"}, + {file = "pillow-11.0.0-cp312-cp312-win32.whl", hash = "sha256:86510e3f5eca0ab87429dd77fafc04693195eec7fd6a137c389c3eeb4cfb77c6"}, + {file = "pillow-11.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:8ec4a89295cd6cd4d1058a5e6aec6bf51e0eaaf9714774e1bfac7cfc9051db47"}, + {file = "pillow-11.0.0-cp312-cp312-win_arm64.whl", hash = "sha256:27a7860107500d813fcd203b4ea19b04babe79448268403172782754870dac25"}, + {file = "pillow-11.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:bcd1fb5bb7b07f64c15618c89efcc2cfa3e95f0e3bcdbaf4642509de1942a699"}, + {file = "pillow-11.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0e038b0745997c7dcaae350d35859c9715c71e92ffb7e0f4a8e8a16732150f38"}, + {file = "pillow-11.0.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ae08bd8ffc41aebf578c2af2f9d8749d91f448b3bfd41d7d9ff573d74f2a6b2"}, + {file = "pillow-11.0.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d69bfd8ec3219ae71bcde1f942b728903cad25fafe3100ba2258b973bd2bc1b2"}, + {file = "pillow-11.0.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:61b887f9ddba63ddf62fd02a3ba7add935d053b6dd7d58998c630e6dbade8527"}, + {file = "pillow-11.0.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:c6a660307ca9d4867caa8d9ca2c2658ab685de83792d1876274991adec7b93fa"}, + {file = "pillow-11.0.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:73e3a0200cdda995c7e43dd47436c1548f87a30bb27fb871f352a22ab8dcf45f"}, + {file = "pillow-11.0.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:fba162b8872d30fea8c52b258a542c5dfd7b235fb5cb352240c8d63b414013eb"}, + {file = "pillow-11.0.0-cp313-cp313-win32.whl", hash = "sha256:f1b82c27e89fffc6da125d5eb0ca6e68017faf5efc078128cfaa42cf5cb38798"}, + {file = "pillow-11.0.0-cp313-cp313-win_amd64.whl", hash = "sha256:8ba470552b48e5835f1d23ecb936bb7f71d206f9dfeee64245f30c3270b994de"}, + {file = "pillow-11.0.0-cp313-cp313-win_arm64.whl", hash = "sha256:846e193e103b41e984ac921b335df59195356ce3f71dcfd155aa79c603873b84"}, + {file = "pillow-11.0.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:4ad70c4214f67d7466bea6a08061eba35c01b1b89eaa098040a35272a8efb22b"}, + {file = "pillow-11.0.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:6ec0d5af64f2e3d64a165f490d96368bb5dea8b8f9ad04487f9ab60dc4bb6003"}, + {file = "pillow-11.0.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c809a70e43c7977c4a42aefd62f0131823ebf7dd73556fa5d5950f5b354087e2"}, + {file = "pillow-11.0.0-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:4b60c9520f7207aaf2e1d94de026682fc227806c6e1f55bba7606d1c94dd623a"}, + {file = "pillow-11.0.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:1e2688958a840c822279fda0086fec1fdab2f95bf2b717b66871c4ad9859d7e8"}, + {file = "pillow-11.0.0-cp313-cp313t-win32.whl", hash = "sha256:607bbe123c74e272e381a8d1957083a9463401f7bd01287f50521ecb05a313f8"}, + {file = "pillow-11.0.0-cp313-cp313t-win_amd64.whl", hash = "sha256:5c39ed17edea3bc69c743a8dd3e9853b7509625c2462532e62baa0732163a904"}, + {file = "pillow-11.0.0-cp313-cp313t-win_arm64.whl", hash = "sha256:75acbbeb05b86bc53cbe7b7e6fe00fbcf82ad7c684b3ad82e3d711da9ba287d3"}, + {file = "pillow-11.0.0-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:2e46773dc9f35a1dd28bd6981332fd7f27bec001a918a72a79b4133cf5291dba"}, + {file = "pillow-11.0.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:2679d2258b7f1192b378e2893a8a0a0ca472234d4c2c0e6bdd3380e8dfa21b6a"}, + {file = "pillow-11.0.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eda2616eb2313cbb3eebbe51f19362eb434b18e3bb599466a1ffa76a033fb916"}, + {file = "pillow-11.0.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:20ec184af98a121fb2da42642dea8a29ec80fc3efbaefb86d8fdd2606619045d"}, + {file = "pillow-11.0.0-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:8594f42df584e5b4bb9281799698403f7af489fba84c34d53d1c4bfb71b7c4e7"}, + {file = "pillow-11.0.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:c12b5ae868897c7338519c03049a806af85b9b8c237b7d675b8c5e089e4a618e"}, + {file = "pillow-11.0.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:70fbbdacd1d271b77b7721fe3cdd2d537bbbd75d29e6300c672ec6bb38d9672f"}, + {file = "pillow-11.0.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:5178952973e588b3f1360868847334e9e3bf49d19e169bbbdfaf8398002419ae"}, + {file = "pillow-11.0.0-cp39-cp39-win32.whl", hash = "sha256:8c676b587da5673d3c75bd67dd2a8cdfeb282ca38a30f37950511766b26858c4"}, + {file = "pillow-11.0.0-cp39-cp39-win_amd64.whl", hash = "sha256:94f3e1780abb45062287b4614a5bc0874519c86a777d4a7ad34978e86428b8dd"}, + {file = "pillow-11.0.0-cp39-cp39-win_arm64.whl", hash = "sha256:290f2cc809f9da7d6d622550bbf4c1e57518212da51b6a30fe8e0a270a5b78bd"}, + {file = "pillow-11.0.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:1187739620f2b365de756ce086fdb3604573337cc28a0d3ac4a01ab6b2d2a6d2"}, + {file = "pillow-11.0.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:fbbcb7b57dc9c794843e3d1258c0fbf0f48656d46ffe9e09b63bbd6e8cd5d0a2"}, + {file = "pillow-11.0.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5d203af30149ae339ad1b4f710d9844ed8796e97fda23ffbc4cc472968a47d0b"}, + {file = "pillow-11.0.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:21a0d3b115009ebb8ac3d2ebec5c2982cc693da935f4ab7bb5c8ebe2f47d36f2"}, + {file = "pillow-11.0.0-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:73853108f56df97baf2bb8b522f3578221e56f646ba345a372c78326710d3830"}, + {file = "pillow-11.0.0-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:e58876c91f97b0952eb766123bfef372792ab3f4e3e1f1a2267834c2ab131734"}, + {file = "pillow-11.0.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:224aaa38177597bb179f3ec87eeefcce8e4f85e608025e9cfac60de237ba6316"}, + {file = "pillow-11.0.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:5bd2d3bdb846d757055910f0a59792d33b555800813c3b39ada1829c372ccb06"}, + {file = "pillow-11.0.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:375b8dd15a1f5d2feafff536d47e22f69625c1aa92f12b339ec0b2ca40263273"}, + {file = "pillow-11.0.0-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:daffdf51ee5db69a82dd127eabecce20729e21f7a3680cf7cbb23f0829189790"}, + {file = "pillow-11.0.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:7326a1787e3c7b0429659e0a944725e1b03eeaa10edd945a86dead1913383944"}, + {file = "pillow-11.0.0.tar.gz", hash = "sha256:72bacbaf24ac003fea9bff9837d1eedb6088758d41e100c1552930151f677739"}, ] [package.extras] -docs = ["furo", "olefile", "sphinx (>=7.3)", "sphinx-copybutton", "sphinx-inline-tabs", "sphinxext-opengraph"] +docs = ["furo", "olefile", "sphinx (>=8.1)", "sphinx-copybutton", "sphinx-inline-tabs", "sphinxext-opengraph"] fpx = ["olefile"] mic = ["olefile"] tests = ["check-manifest", "coverage", "defusedxml", "markdown2", "olefile", "packaging", "pyroma", "pytest", "pytest-cov", "pytest-timeout"] @@ -2317,26 +2097,6 @@ nodeenv = ">=0.11.1" pyyaml = ">=5.1" virtualenv = ">=20.10.0" -[[package]] -name = "protobuf" -version = "5.28.2" -description = "" -optional = false -python-versions = ">=3.8" -files = [ - {file = "protobuf-5.28.2-cp310-abi3-win32.whl", hash = "sha256:eeea10f3dc0ac7e6b4933d32db20662902b4ab81bf28df12218aa389e9c2102d"}, - {file = "protobuf-5.28.2-cp310-abi3-win_amd64.whl", hash = "sha256:2c69461a7fcc8e24be697624c09a839976d82ae75062b11a0972e41fd2cd9132"}, - {file = "protobuf-5.28.2-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:a8b9403fc70764b08d2f593ce44f1d2920c5077bf7d311fefec999f8c40f78b7"}, - {file = "protobuf-5.28.2-cp38-abi3-manylinux2014_aarch64.whl", hash = "sha256:35cfcb15f213449af7ff6198d6eb5f739c37d7e4f1c09b5d0641babf2cc0c68f"}, - {file = "protobuf-5.28.2-cp38-abi3-manylinux2014_x86_64.whl", hash = "sha256:5e8a95246d581eef20471b5d5ba010d55f66740942b95ba9b872d918c459452f"}, - {file = "protobuf-5.28.2-cp38-cp38-win32.whl", hash = "sha256:87317e9bcda04a32f2ee82089a204d3a2f0d3c8aeed16568c7daf4756e4f1fe0"}, - {file = "protobuf-5.28.2-cp38-cp38-win_amd64.whl", hash = "sha256:c0ea0123dac3399a2eeb1a1443d82b7afc9ff40241433296769f7da42d142ec3"}, - {file = "protobuf-5.28.2-cp39-cp39-win32.whl", hash = "sha256:ca53faf29896c526863366a52a8f4d88e69cd04ec9571ed6082fa117fac3ab36"}, - {file = "protobuf-5.28.2-cp39-cp39-win_amd64.whl", hash = "sha256:8ddc60bf374785fb7cb12510b267f59067fa10087325b8e1855b898a0d81d276"}, - {file = "protobuf-5.28.2-py3-none-any.whl", hash = "sha256:52235802093bd8a2811abbe8bf0ab9c5f54cca0a751fdd3f6ac2a21438bffece"}, - {file = "protobuf-5.28.2.tar.gz", hash = "sha256:59379674ff119717404f7454647913787034f03fe7049cbef1d74a97bb4593f0"}, -] - [[package]] name = "psutil" version = "5.9.8" @@ -2367,109 +2127,104 @@ test = ["enum34", "ipaddress", "mock", "pywin32", "wmi"] [[package]] name = "psycopg2-binary" -version = "2.9.9" +version = "2.9.10" description = "psycopg2 - Python-PostgreSQL Database Adapter" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "psycopg2-binary-2.9.9.tar.gz", hash = "sha256:7f01846810177d829c7692f1f5ada8096762d9172af1b1a28d4ab5b77c923c1c"}, - {file = "psycopg2_binary-2.9.9-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c2470da5418b76232f02a2fcd2229537bb2d5a7096674ce61859c3229f2eb202"}, - {file = "psycopg2_binary-2.9.9-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c6af2a6d4b7ee9615cbb162b0738f6e1fd1f5c3eda7e5da17861eacf4c717ea7"}, - {file = "psycopg2_binary-2.9.9-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:75723c3c0fbbf34350b46a3199eb50638ab22a0228f93fb472ef4d9becc2382b"}, - {file = "psycopg2_binary-2.9.9-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:83791a65b51ad6ee6cf0845634859d69a038ea9b03d7b26e703f94c7e93dbcf9"}, - {file = "psycopg2_binary-2.9.9-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0ef4854e82c09e84cc63084a9e4ccd6d9b154f1dbdd283efb92ecd0b5e2b8c84"}, - {file = "psycopg2_binary-2.9.9-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ed1184ab8f113e8d660ce49a56390ca181f2981066acc27cf637d5c1e10ce46e"}, - {file = "psycopg2_binary-2.9.9-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:d2997c458c690ec2bc6b0b7ecbafd02b029b7b4283078d3b32a852a7ce3ddd98"}, - {file = "psycopg2_binary-2.9.9-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:b58b4710c7f4161b5e9dcbe73bb7c62d65670a87df7bcce9e1faaad43e715245"}, - {file = "psycopg2_binary-2.9.9-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:0c009475ee389757e6e34611d75f6e4f05f0cf5ebb76c6037508318e1a1e0d7e"}, - {file = "psycopg2_binary-2.9.9-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:8dbf6d1bc73f1d04ec1734bae3b4fb0ee3cb2a493d35ede9badbeb901fb40f6f"}, - {file = "psycopg2_binary-2.9.9-cp310-cp310-win32.whl", hash = "sha256:3f78fd71c4f43a13d342be74ebbc0666fe1f555b8837eb113cb7416856c79682"}, - {file = "psycopg2_binary-2.9.9-cp310-cp310-win_amd64.whl", hash = "sha256:876801744b0dee379e4e3c38b76fc89f88834bb15bf92ee07d94acd06ec890a0"}, - {file = "psycopg2_binary-2.9.9-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ee825e70b1a209475622f7f7b776785bd68f34af6e7a46e2e42f27b659b5bc26"}, - {file = "psycopg2_binary-2.9.9-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1ea665f8ce695bcc37a90ee52de7a7980be5161375d42a0b6c6abedbf0d81f0f"}, - {file = "psycopg2_binary-2.9.9-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:143072318f793f53819048fdfe30c321890af0c3ec7cb1dfc9cc87aa88241de2"}, - {file = "psycopg2_binary-2.9.9-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c332c8d69fb64979ebf76613c66b985414927a40f8defa16cf1bc028b7b0a7b0"}, - {file = "psycopg2_binary-2.9.9-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f7fc5a5acafb7d6ccca13bfa8c90f8c51f13d8fb87d95656d3950f0158d3ce53"}, - {file = "psycopg2_binary-2.9.9-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:977646e05232579d2e7b9c59e21dbe5261f403a88417f6a6512e70d3f8a046be"}, - {file = "psycopg2_binary-2.9.9-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:b6356793b84728d9d50ead16ab43c187673831e9d4019013f1402c41b1db9b27"}, - {file = "psycopg2_binary-2.9.9-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:bc7bb56d04601d443f24094e9e31ae6deec9ccb23581f75343feebaf30423359"}, - {file = "psycopg2_binary-2.9.9-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:77853062a2c45be16fd6b8d6de2a99278ee1d985a7bd8b103e97e41c034006d2"}, - {file = "psycopg2_binary-2.9.9-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:78151aa3ec21dccd5cdef6c74c3e73386dcdfaf19bced944169697d7ac7482fc"}, - {file = "psycopg2_binary-2.9.9-cp311-cp311-win32.whl", hash = "sha256:dc4926288b2a3e9fd7b50dc6a1909a13bbdadfc67d93f3374d984e56f885579d"}, - {file = "psycopg2_binary-2.9.9-cp311-cp311-win_amd64.whl", hash = "sha256:b76bedd166805480ab069612119ea636f5ab8f8771e640ae103e05a4aae3e417"}, - {file = "psycopg2_binary-2.9.9-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:8532fd6e6e2dc57bcb3bc90b079c60de896d2128c5d9d6f24a63875a95a088cf"}, - {file = "psycopg2_binary-2.9.9-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:b0605eaed3eb239e87df0d5e3c6489daae3f7388d455d0c0b4df899519c6a38d"}, - {file = "psycopg2_binary-2.9.9-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8f8544b092a29a6ddd72f3556a9fcf249ec412e10ad28be6a0c0d948924f2212"}, - {file = "psycopg2_binary-2.9.9-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2d423c8d8a3c82d08fe8af900ad5b613ce3632a1249fd6a223941d0735fce493"}, - {file = "psycopg2_binary-2.9.9-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2e5afae772c00980525f6d6ecf7cbca55676296b580c0e6abb407f15f3706996"}, - {file = "psycopg2_binary-2.9.9-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6e6f98446430fdf41bd36d4faa6cb409f5140c1c2cf58ce0bbdaf16af7d3f119"}, - {file = "psycopg2_binary-2.9.9-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:c77e3d1862452565875eb31bdb45ac62502feabbd53429fdc39a1cc341d681ba"}, - {file = "psycopg2_binary-2.9.9-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:cb16c65dcb648d0a43a2521f2f0a2300f40639f6f8c1ecbc662141e4e3e1ee07"}, - {file = "psycopg2_binary-2.9.9-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:911dda9c487075abd54e644ccdf5e5c16773470a6a5d3826fda76699410066fb"}, - {file = "psycopg2_binary-2.9.9-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:57fede879f08d23c85140a360c6a77709113efd1c993923c59fde17aa27599fe"}, - {file = "psycopg2_binary-2.9.9-cp312-cp312-win32.whl", hash = "sha256:64cf30263844fa208851ebb13b0732ce674d8ec6a0c86a4e160495d299ba3c93"}, - {file = "psycopg2_binary-2.9.9-cp312-cp312-win_amd64.whl", hash = "sha256:81ff62668af011f9a48787564ab7eded4e9fb17a4a6a74af5ffa6a457400d2ab"}, - {file = "psycopg2_binary-2.9.9-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:2293b001e319ab0d869d660a704942c9e2cce19745262a8aba2115ef41a0a42a"}, - {file = "psycopg2_binary-2.9.9-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:03ef7df18daf2c4c07e2695e8cfd5ee7f748a1d54d802330985a78d2a5a6dca9"}, - {file = "psycopg2_binary-2.9.9-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0a602ea5aff39bb9fac6308e9c9d82b9a35c2bf288e184a816002c9fae930b77"}, - {file = "psycopg2_binary-2.9.9-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8359bf4791968c5a78c56103702000105501adb557f3cf772b2c207284273984"}, - {file = "psycopg2_binary-2.9.9-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:275ff571376626195ab95a746e6a04c7df8ea34638b99fc11160de91f2fef503"}, - {file = "psycopg2_binary-2.9.9-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:f9b5571d33660d5009a8b3c25dc1db560206e2d2f89d3df1cb32d72c0d117d52"}, - {file = "psycopg2_binary-2.9.9-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:420f9bbf47a02616e8554e825208cb947969451978dceb77f95ad09c37791dae"}, - {file = "psycopg2_binary-2.9.9-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:4154ad09dac630a0f13f37b583eae260c6aa885d67dfbccb5b02c33f31a6d420"}, - {file = "psycopg2_binary-2.9.9-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:a148c5d507bb9b4f2030a2025c545fccb0e1ef317393eaba42e7eabd28eb6041"}, - {file = "psycopg2_binary-2.9.9-cp37-cp37m-win32.whl", hash = "sha256:68fc1f1ba168724771e38bee37d940d2865cb0f562380a1fb1ffb428b75cb692"}, - {file = "psycopg2_binary-2.9.9-cp37-cp37m-win_amd64.whl", hash = "sha256:281309265596e388ef483250db3640e5f414168c5a67e9c665cafce9492eda2f"}, - {file = "psycopg2_binary-2.9.9-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:60989127da422b74a04345096c10d416c2b41bd7bf2a380eb541059e4e999980"}, - {file = "psycopg2_binary-2.9.9-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:246b123cc54bb5361588acc54218c8c9fb73068bf227a4a531d8ed56fa3ca7d6"}, - {file = "psycopg2_binary-2.9.9-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:34eccd14566f8fe14b2b95bb13b11572f7c7d5c36da61caf414d23b91fcc5d94"}, - {file = "psycopg2_binary-2.9.9-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:18d0ef97766055fec15b5de2c06dd8e7654705ce3e5e5eed3b6651a1d2a9a152"}, - {file = "psycopg2_binary-2.9.9-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d3f82c171b4ccd83bbaf35aa05e44e690113bd4f3b7b6cc54d2219b132f3ae55"}, - {file = "psycopg2_binary-2.9.9-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ead20f7913a9c1e894aebe47cccf9dc834e1618b7aa96155d2091a626e59c972"}, - {file = "psycopg2_binary-2.9.9-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:ca49a8119c6cbd77375ae303b0cfd8c11f011abbbd64601167ecca18a87e7cdd"}, - {file = "psycopg2_binary-2.9.9-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:323ba25b92454adb36fa425dc5cf6f8f19f78948cbad2e7bc6cdf7b0d7982e59"}, - {file = "psycopg2_binary-2.9.9-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:1236ed0952fbd919c100bc839eaa4a39ebc397ed1c08a97fc45fee2a595aa1b3"}, - {file = "psycopg2_binary-2.9.9-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:729177eaf0aefca0994ce4cffe96ad3c75e377c7b6f4efa59ebf003b6d398716"}, - {file = "psycopg2_binary-2.9.9-cp38-cp38-win32.whl", hash = "sha256:804d99b24ad523a1fe18cc707bf741670332f7c7412e9d49cb5eab67e886b9b5"}, - {file = "psycopg2_binary-2.9.9-cp38-cp38-win_amd64.whl", hash = "sha256:a6cdcc3ede532f4a4b96000b6362099591ab4a3e913d70bcbac2b56c872446f7"}, - {file = "psycopg2_binary-2.9.9-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:72dffbd8b4194858d0941062a9766f8297e8868e1dd07a7b36212aaa90f49472"}, - {file = "psycopg2_binary-2.9.9-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:30dcc86377618a4c8f3b72418df92e77be4254d8f89f14b8e8f57d6d43603c0f"}, - {file = "psycopg2_binary-2.9.9-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:31a34c508c003a4347d389a9e6fcc2307cc2150eb516462a7a17512130de109e"}, - {file = "psycopg2_binary-2.9.9-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:15208be1c50b99203fe88d15695f22a5bed95ab3f84354c494bcb1d08557df67"}, - {file = "psycopg2_binary-2.9.9-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1873aade94b74715be2246321c8650cabf5a0d098a95bab81145ffffa4c13876"}, - {file = "psycopg2_binary-2.9.9-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3a58c98a7e9c021f357348867f537017057c2ed7f77337fd914d0bedb35dace7"}, - {file = "psycopg2_binary-2.9.9-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:4686818798f9194d03c9129a4d9a702d9e113a89cb03bffe08c6cf799e053291"}, - {file = "psycopg2_binary-2.9.9-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:ebdc36bea43063116f0486869652cb2ed7032dbc59fbcb4445c4862b5c1ecf7f"}, - {file = "psycopg2_binary-2.9.9-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:ca08decd2697fdea0aea364b370b1249d47336aec935f87b8bbfd7da5b2ee9c1"}, - {file = "psycopg2_binary-2.9.9-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ac05fb791acf5e1a3e39402641827780fe44d27e72567a000412c648a85ba860"}, - {file = "psycopg2_binary-2.9.9-cp39-cp39-win32.whl", hash = "sha256:9dba73be7305b399924709b91682299794887cbbd88e38226ed9f6712eabee90"}, - {file = "psycopg2_binary-2.9.9-cp39-cp39-win_amd64.whl", hash = "sha256:f7ae5d65ccfbebdfa761585228eb4d0df3a8b15cfb53bd953e713e09fbb12957"}, + {file = "psycopg2-binary-2.9.10.tar.gz", hash = "sha256:4b3df0e6990aa98acda57d983942eff13d824135fe2250e6522edaa782a06de2"}, + {file = "psycopg2_binary-2.9.10-cp310-cp310-macosx_12_0_x86_64.whl", hash = "sha256:0ea8e3d0ae83564f2fc554955d327fa081d065c8ca5cc6d2abb643e2c9c1200f"}, + {file = "psycopg2_binary-2.9.10-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:3e9c76f0ac6f92ecfc79516a8034a544926430f7b080ec5a0537bca389ee0906"}, + {file = "psycopg2_binary-2.9.10-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2ad26b467a405c798aaa1458ba09d7e2b6e5f96b1ce0ac15d82fd9f95dc38a92"}, + {file = "psycopg2_binary-2.9.10-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:270934a475a0e4b6925b5f804e3809dd5f90f8613621d062848dd82f9cd62007"}, + {file = "psycopg2_binary-2.9.10-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:48b338f08d93e7be4ab2b5f1dbe69dc5e9ef07170fe1f86514422076d9c010d0"}, + {file = "psycopg2_binary-2.9.10-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f4152f8f76d2023aac16285576a9ecd2b11a9895373a1f10fd9db54b3ff06b4"}, + {file = "psycopg2_binary-2.9.10-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:32581b3020c72d7a421009ee1c6bf4a131ef5f0a968fab2e2de0c9d2bb4577f1"}, + {file = "psycopg2_binary-2.9.10-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:2ce3e21dc3437b1d960521eca599d57408a695a0d3c26797ea0f72e834c7ffe5"}, + {file = "psycopg2_binary-2.9.10-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:e984839e75e0b60cfe75e351db53d6db750b00de45644c5d1f7ee5d1f34a1ce5"}, + {file = "psycopg2_binary-2.9.10-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:3c4745a90b78e51d9ba06e2088a2fe0c693ae19cc8cb051ccda44e8df8a6eb53"}, + {file = "psycopg2_binary-2.9.10-cp310-cp310-win32.whl", hash = "sha256:e5720a5d25e3b99cd0dc5c8a440570469ff82659bb09431c1439b92caf184d3b"}, + {file = "psycopg2_binary-2.9.10-cp310-cp310-win_amd64.whl", hash = "sha256:3c18f74eb4386bf35e92ab2354a12c17e5eb4d9798e4c0ad3a00783eae7cd9f1"}, + {file = "psycopg2_binary-2.9.10-cp311-cp311-macosx_12_0_x86_64.whl", hash = "sha256:04392983d0bb89a8717772a193cfaac58871321e3ec69514e1c4e0d4957b5aff"}, + {file = "psycopg2_binary-2.9.10-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:1a6784f0ce3fec4edc64e985865c17778514325074adf5ad8f80636cd029ef7c"}, + {file = "psycopg2_binary-2.9.10-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b5f86c56eeb91dc3135b3fd8a95dc7ae14c538a2f3ad77a19645cf55bab1799c"}, + {file = "psycopg2_binary-2.9.10-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2b3d2491d4d78b6b14f76881905c7a8a8abcf974aad4a8a0b065273a0ed7a2cb"}, + {file = "psycopg2_binary-2.9.10-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2286791ececda3a723d1910441c793be44625d86d1a4e79942751197f4d30341"}, + {file = "psycopg2_binary-2.9.10-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:512d29bb12608891e349af6a0cccedce51677725a921c07dba6342beaf576f9a"}, + {file = "psycopg2_binary-2.9.10-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:5a507320c58903967ef7384355a4da7ff3f28132d679aeb23572753cbf2ec10b"}, + {file = "psycopg2_binary-2.9.10-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:6d4fa1079cab9018f4d0bd2db307beaa612b0d13ba73b5c6304b9fe2fb441ff7"}, + {file = "psycopg2_binary-2.9.10-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:851485a42dbb0bdc1edcdabdb8557c09c9655dfa2ca0460ff210522e073e319e"}, + {file = "psycopg2_binary-2.9.10-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:35958ec9e46432d9076286dda67942ed6d968b9c3a6a2fd62b48939d1d78bf68"}, + {file = "psycopg2_binary-2.9.10-cp311-cp311-win32.whl", hash = "sha256:ecced182e935529727401b24d76634a357c71c9275b356efafd8a2a91ec07392"}, + {file = "psycopg2_binary-2.9.10-cp311-cp311-win_amd64.whl", hash = "sha256:ee0e8c683a7ff25d23b55b11161c2663d4b099770f6085ff0a20d4505778d6b4"}, + {file = "psycopg2_binary-2.9.10-cp312-cp312-macosx_12_0_x86_64.whl", hash = "sha256:880845dfe1f85d9d5f7c412efea7a08946a46894537e4e5d091732eb1d34d9a0"}, + {file = "psycopg2_binary-2.9.10-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:9440fa522a79356aaa482aa4ba500b65f28e5d0e63b801abf6aa152a29bd842a"}, + {file = "psycopg2_binary-2.9.10-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e3923c1d9870c49a2d44f795df0c889a22380d36ef92440ff618ec315757e539"}, + {file = "psycopg2_binary-2.9.10-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7b2c956c028ea5de47ff3a8d6b3cc3330ab45cf0b7c3da35a2d6ff8420896526"}, + {file = "psycopg2_binary-2.9.10-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f758ed67cab30b9a8d2833609513ce4d3bd027641673d4ebc9c067e4d208eec1"}, + {file = "psycopg2_binary-2.9.10-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8cd9b4f2cfab88ed4a9106192de509464b75a906462fb846b936eabe45c2063e"}, + {file = "psycopg2_binary-2.9.10-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6dc08420625b5a20b53551c50deae6e231e6371194fa0651dbe0fb206452ae1f"}, + {file = "psycopg2_binary-2.9.10-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:d7cd730dfa7c36dbe8724426bf5612798734bff2d3c3857f36f2733f5bfc7c00"}, + {file = "psycopg2_binary-2.9.10-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:155e69561d54d02b3c3209545fb08938e27889ff5a10c19de8d23eb5a41be8a5"}, + {file = "psycopg2_binary-2.9.10-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:c3cc28a6fd5a4a26224007712e79b81dbaee2ffb90ff406256158ec4d7b52b47"}, + {file = "psycopg2_binary-2.9.10-cp312-cp312-win32.whl", hash = "sha256:ec8a77f521a17506a24a5f626cb2aee7850f9b69a0afe704586f63a464f3cd64"}, + {file = "psycopg2_binary-2.9.10-cp312-cp312-win_amd64.whl", hash = "sha256:18c5ee682b9c6dd3696dad6e54cc7ff3a1a9020df6a5c0f861ef8bfd338c3ca0"}, + {file = "psycopg2_binary-2.9.10-cp313-cp313-macosx_12_0_x86_64.whl", hash = "sha256:26540d4a9a4e2b096f1ff9cce51253d0504dca5a85872c7f7be23be5a53eb18d"}, + {file = "psycopg2_binary-2.9.10-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:e217ce4d37667df0bc1c397fdcd8de5e81018ef305aed9415c3b093faaeb10fb"}, + {file = "psycopg2_binary-2.9.10-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:245159e7ab20a71d989da00f280ca57da7641fa2cdcf71749c193cea540a74f7"}, + {file = "psycopg2_binary-2.9.10-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3c4ded1a24b20021ebe677b7b08ad10bf09aac197d6943bfe6fec70ac4e4690d"}, + {file = "psycopg2_binary-2.9.10-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3abb691ff9e57d4a93355f60d4f4c1dd2d68326c968e7db17ea96df3c023ef73"}, + {file = "psycopg2_binary-2.9.10-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8608c078134f0b3cbd9f89b34bd60a943b23fd33cc5f065e8d5f840061bd0673"}, + {file = "psycopg2_binary-2.9.10-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:230eeae2d71594103cd5b93fd29d1ace6420d0b86f4778739cb1a5a32f607d1f"}, + {file = "psycopg2_binary-2.9.10-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:bb89f0a835bcfc1d42ccd5f41f04870c1b936d8507c6df12b7737febc40f0909"}, + {file = "psycopg2_binary-2.9.10-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:f0c2d907a1e102526dd2986df638343388b94c33860ff3bbe1384130828714b1"}, + {file = "psycopg2_binary-2.9.10-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:f8157bed2f51db683f31306aa497311b560f2265998122abe1dce6428bd86567"}, + {file = "psycopg2_binary-2.9.10-cp38-cp38-macosx_12_0_x86_64.whl", hash = "sha256:eb09aa7f9cecb45027683bb55aebaaf45a0df8bf6de68801a6afdc7947bb09d4"}, + {file = "psycopg2_binary-2.9.10-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b73d6d7f0ccdad7bc43e6d34273f70d587ef62f824d7261c4ae9b8b1b6af90e8"}, + {file = "psycopg2_binary-2.9.10-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ce5ab4bf46a211a8e924d307c1b1fcda82368586a19d0a24f8ae166f5c784864"}, + {file = "psycopg2_binary-2.9.10-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:056470c3dc57904bbf63d6f534988bafc4e970ffd50f6271fc4ee7daad9498a5"}, + {file = "psycopg2_binary-2.9.10-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:73aa0e31fa4bb82578f3a6c74a73c273367727de397a7a0f07bd83cbea696baa"}, + {file = "psycopg2_binary-2.9.10-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:8de718c0e1c4b982a54b41779667242bc630b2197948405b7bd8ce16bcecac92"}, + {file = "psycopg2_binary-2.9.10-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:5c370b1e4975df846b0277b4deba86419ca77dbc25047f535b0bb03d1a544d44"}, + {file = "psycopg2_binary-2.9.10-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:ffe8ed017e4ed70f68b7b371d84b7d4a790368db9203dfc2d222febd3a9c8863"}, + {file = "psycopg2_binary-2.9.10-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:8aecc5e80c63f7459a1a2ab2c64df952051df196294d9f739933a9f6687e86b3"}, + {file = "psycopg2_binary-2.9.10-cp39-cp39-macosx_12_0_x86_64.whl", hash = "sha256:7a813c8bdbaaaab1f078014b9b0b13f5de757e2b5d9be6403639b298a04d218b"}, + {file = "psycopg2_binary-2.9.10-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d00924255d7fc916ef66e4bf22f354a940c67179ad3fd7067d7a0a9c84d2fbfc"}, + {file = "psycopg2_binary-2.9.10-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7559bce4b505762d737172556a4e6ea8a9998ecac1e39b5233465093e8cee697"}, + {file = "psycopg2_binary-2.9.10-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e8b58f0a96e7a1e341fc894f62c1177a7c83febebb5ff9123b579418fdc8a481"}, + {file = "psycopg2_binary-2.9.10-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6b269105e59ac96aba877c1707c600ae55711d9dcd3fc4b5012e4af68e30c648"}, + {file = "psycopg2_binary-2.9.10-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:79625966e176dc97ddabc142351e0409e28acf4660b88d1cf6adb876d20c490d"}, + {file = "psycopg2_binary-2.9.10-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:8aabf1c1a04584c168984ac678a668094d831f152859d06e055288fa515e4d30"}, + {file = "psycopg2_binary-2.9.10-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:19721ac03892001ee8fdd11507e6a2e01f4e37014def96379411ca99d78aeb2c"}, + {file = "psycopg2_binary-2.9.10-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:7f5d859928e635fa3ce3477704acee0f667b3a3d3e4bb109f2b18d4005f38287"}, + {file = "psycopg2_binary-2.9.10-cp39-cp39-win32.whl", hash = "sha256:3216ccf953b3f267691c90c6fe742e45d890d8272326b4a8b20850a03d05b7b8"}, + {file = "psycopg2_binary-2.9.10-cp39-cp39-win_amd64.whl", hash = "sha256:30e34c4e97964805f715206c7b789d54a78b70f3ff19fbe590104b71c45600e5"}, ] [[package]] name = "pyasn1" -version = "0.5.1" +version = "0.6.1" description = "Pure-Python implementation of ASN.1 types and DER/BER/CER codecs (X.208)" optional = false -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7" +python-versions = ">=3.8" files = [ - {file = "pyasn1-0.5.1-py2.py3-none-any.whl", hash = "sha256:4439847c58d40b1d0a573d07e3856e95333f1976294494c325775aeca506eb58"}, - {file = "pyasn1-0.5.1.tar.gz", hash = "sha256:6d391a96e59b23130a5cfa74d6fd7f388dbbe26cc8f1edf39fdddf08d9d6676c"}, + {file = "pyasn1-0.6.1-py3-none-any.whl", hash = "sha256:0d632f46f2ba09143da3a8afe9e33fb6f92fa2320ab7e886e2d0f7672af84629"}, + {file = "pyasn1-0.6.1.tar.gz", hash = "sha256:6f580d2bdd84365380830acf45550f2511469f673cb4a5ae3857a3170128b034"}, ] [[package]] name = "pyasn1-modules" -version = "0.3.0" +version = "0.4.1" description = "A collection of ASN.1-based protocols modules" optional = false -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7" +python-versions = ">=3.8" files = [ - {file = "pyasn1_modules-0.3.0-py2.py3-none-any.whl", hash = "sha256:d3ccd6ed470d9ffbc716be08bd90efbd44d0734bc9303818f7336070984a162d"}, - {file = "pyasn1_modules-0.3.0.tar.gz", hash = "sha256:5bd01446b736eb9d31512a30d46c1ac3395d676c6f3cafa4c03eb54b9925631c"}, + {file = "pyasn1_modules-0.4.1-py3-none-any.whl", hash = "sha256:49bfa96b45a292b711e986f222502c1c9a5e1f4e568fc30e2574a6c7d07838fd"}, + {file = "pyasn1_modules-0.4.1.tar.gz", hash = "sha256:c28e2dbf9c06ad61c71a075c7e0f9fd0f1b0bb2d2ad4377f240d33ac2ab60a7c"}, ] [package.dependencies] -pyasn1 = ">=0.4.6,<0.6.0" +pyasn1 = ">=0.4.6,<0.7.0" [[package]] name = "pycparser" @@ -2525,43 +2280,43 @@ files = [ [[package]] name = "pycryptodomex" -version = "3.20.0" +version = "3.21.0" description = "Cryptographic library for Python" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7" files = [ - {file = "pycryptodomex-3.20.0-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:645bd4ca6f543685d643dadf6a856cc382b654cc923460e3a10a49c1b3832aeb"}, - {file = "pycryptodomex-3.20.0-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:ff5c9a67f8a4fba4aed887216e32cbc48f2a6fb2673bb10a99e43be463e15913"}, - {file = "pycryptodomex-3.20.0-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:8ee606964553c1a0bc74057dd8782a37d1c2bc0f01b83193b6f8bb14523b877b"}, - {file = "pycryptodomex-3.20.0-cp27-cp27m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7805830e0c56d88f4d491fa5ac640dfc894c5ec570d1ece6ed1546e9df2e98d6"}, - {file = "pycryptodomex-3.20.0-cp27-cp27m-musllinux_1_1_aarch64.whl", hash = "sha256:bc3ee1b4d97081260d92ae813a83de4d2653206967c4a0a017580f8b9548ddbc"}, - {file = "pycryptodomex-3.20.0-cp27-cp27m-win32.whl", hash = "sha256:8af1a451ff9e123d0d8bd5d5e60f8e3315c3a64f3cdd6bc853e26090e195cdc8"}, - {file = "pycryptodomex-3.20.0-cp27-cp27m-win_amd64.whl", hash = "sha256:cbe71b6712429650e3883dc81286edb94c328ffcd24849accac0a4dbcc76958a"}, - {file = "pycryptodomex-3.20.0-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:76bd15bb65c14900d98835fcd10f59e5e0435077431d3a394b60b15864fddd64"}, - {file = "pycryptodomex-3.20.0-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:653b29b0819605fe0898829c8ad6400a6ccde096146730c2da54eede9b7b8baa"}, - {file = "pycryptodomex-3.20.0-cp27-cp27mu-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:62a5ec91388984909bb5398ea49ee61b68ecb579123694bffa172c3b0a107079"}, - {file = "pycryptodomex-3.20.0-cp27-cp27mu-musllinux_1_1_aarch64.whl", hash = "sha256:108e5f1c1cd70ffce0b68739c75734437c919d2eaec8e85bffc2c8b4d2794305"}, - {file = "pycryptodomex-3.20.0-cp35-abi3-macosx_10_9_universal2.whl", hash = "sha256:59af01efb011b0e8b686ba7758d59cf4a8263f9ad35911bfe3f416cee4f5c08c"}, - {file = "pycryptodomex-3.20.0-cp35-abi3-macosx_10_9_x86_64.whl", hash = "sha256:82ee7696ed8eb9a82c7037f32ba9b7c59e51dda6f105b39f043b6ef293989cb3"}, - {file = "pycryptodomex-3.20.0-cp35-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:91852d4480a4537d169c29a9d104dda44094c78f1f5b67bca76c29a91042b623"}, - {file = "pycryptodomex-3.20.0-cp35-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bca649483d5ed251d06daf25957f802e44e6bb6df2e8f218ae71968ff8f8edc4"}, - {file = "pycryptodomex-3.20.0-cp35-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6e186342cfcc3aafaad565cbd496060e5a614b441cacc3995ef0091115c1f6c5"}, - {file = "pycryptodomex-3.20.0-cp35-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:25cd61e846aaab76d5791d006497134602a9e451e954833018161befc3b5b9ed"}, - {file = "pycryptodomex-3.20.0-cp35-abi3-musllinux_1_1_i686.whl", hash = "sha256:9c682436c359b5ada67e882fec34689726a09c461efd75b6ea77b2403d5665b7"}, - {file = "pycryptodomex-3.20.0-cp35-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:7a7a8f33a1f1fb762ede6cc9cbab8f2a9ba13b196bfaf7bc6f0b39d2ba315a43"}, - {file = "pycryptodomex-3.20.0-cp35-abi3-win32.whl", hash = "sha256:c39778fd0548d78917b61f03c1fa8bfda6cfcf98c767decf360945fe6f97461e"}, - {file = "pycryptodomex-3.20.0-cp35-abi3-win_amd64.whl", hash = "sha256:2a47bcc478741b71273b917232f521fd5704ab4b25d301669879e7273d3586cc"}, - {file = "pycryptodomex-3.20.0-pp27-pypy_73-manylinux2010_x86_64.whl", hash = "sha256:1be97461c439a6af4fe1cf8bf6ca5936d3db252737d2f379cc6b2e394e12a458"}, - {file = "pycryptodomex-3.20.0-pp27-pypy_73-win32.whl", hash = "sha256:19764605feea0df966445d46533729b645033f134baeb3ea26ad518c9fdf212c"}, - {file = "pycryptodomex-3.20.0-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:f2e497413560e03421484189a6b65e33fe800d3bd75590e6d78d4dfdb7accf3b"}, - {file = "pycryptodomex-3.20.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e48217c7901edd95f9f097feaa0388da215ed14ce2ece803d3f300b4e694abea"}, - {file = "pycryptodomex-3.20.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d00fe8596e1cc46b44bf3907354e9377aa030ec4cd04afbbf6e899fc1e2a7781"}, - {file = "pycryptodomex-3.20.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:88afd7a3af7ddddd42c2deda43d53d3dfc016c11327d0915f90ca34ebda91499"}, - {file = "pycryptodomex-3.20.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:d3584623e68a5064a04748fb6d76117a21a7cb5eaba20608a41c7d0c61721794"}, - {file = "pycryptodomex-3.20.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0daad007b685db36d977f9de73f61f8da2a7104e20aca3effd30752fd56f73e1"}, - {file = "pycryptodomex-3.20.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5dcac11031a71348faaed1f403a0debd56bf5404232284cf8c761ff918886ebc"}, - {file = "pycryptodomex-3.20.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:69138068268127cd605e03438312d8f271135a33140e2742b417d027a0539427"}, - {file = "pycryptodomex-3.20.0.tar.gz", hash = "sha256:7a710b79baddd65b806402e14766c721aee8fb83381769c27920f26476276c1e"}, + {file = "pycryptodomex-3.21.0-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:dbeb84a399373df84a69e0919c1d733b89e049752426041deeb30d68e9867822"}, + {file = "pycryptodomex-3.21.0-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:a192fb46c95489beba9c3f002ed7d93979423d1b2a53eab8771dbb1339eb3ddd"}, + {file = "pycryptodomex-3.21.0-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:1233443f19d278c72c4daae749872a4af3787a813e05c3561c73ab0c153c7b0f"}, + {file = "pycryptodomex-3.21.0-cp27-cp27m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bbb07f88e277162b8bfca7134b34f18b400d84eac7375ce73117f865e3c80d4c"}, + {file = "pycryptodomex-3.21.0-cp27-cp27m-musllinux_1_1_aarch64.whl", hash = "sha256:e859e53d983b7fe18cb8f1b0e29d991a5c93be2c8dd25db7db1fe3bd3617f6f9"}, + {file = "pycryptodomex-3.21.0-cp27-cp27m-win32.whl", hash = "sha256:ef046b2e6c425647971b51424f0f88d8a2e0a2a63d3531817968c42078895c00"}, + {file = "pycryptodomex-3.21.0-cp27-cp27m-win_amd64.whl", hash = "sha256:da76ebf6650323eae7236b54b1b1f0e57c16483be6e3c1ebf901d4ada47563b6"}, + {file = "pycryptodomex-3.21.0-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:c07e64867a54f7e93186a55bec08a18b7302e7bee1b02fd84c6089ec215e723a"}, + {file = "pycryptodomex-3.21.0-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:56435c7124dd0ce0c8bdd99c52e5d183a0ca7fdcd06c5d5509423843f487dd0b"}, + {file = "pycryptodomex-3.21.0-cp27-cp27mu-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:65d275e3f866cf6fe891411be9c1454fb58809ccc5de6d3770654c47197acd65"}, + {file = "pycryptodomex-3.21.0-cp27-cp27mu-musllinux_1_1_aarch64.whl", hash = "sha256:5241bdb53bcf32a9568770a6584774b1b8109342bd033398e4ff2da052123832"}, + {file = "pycryptodomex-3.21.0-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:34325b84c8b380675fd2320d0649cdcbc9cf1e0d1526edbe8fce43ed858cdc7e"}, + {file = "pycryptodomex-3.21.0-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:103c133d6cd832ae7266feb0a65b69e3a5e4dbbd6f3a3ae3211a557fd653f516"}, + {file = "pycryptodomex-3.21.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:77ac2ea80bcb4b4e1c6a596734c775a1615d23e31794967416afc14852a639d3"}, + {file = "pycryptodomex-3.21.0-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9aa0cf13a1a1128b3e964dc667e5fe5c6235f7d7cfb0277213f0e2a783837cc2"}, + {file = "pycryptodomex-3.21.0-cp36-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:46eb1f0c8d309da63a2064c28de54e5e614ad17b7e2f88df0faef58ce192fc7b"}, + {file = "pycryptodomex-3.21.0-cp36-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:cc7e111e66c274b0df5f4efa679eb31e23c7545d702333dfd2df10ab02c2a2ce"}, + {file = "pycryptodomex-3.21.0-cp36-abi3-musllinux_1_2_i686.whl", hash = "sha256:770d630a5c46605ec83393feaa73a9635a60e55b112e1fb0c3cea84c2897aa0a"}, + {file = "pycryptodomex-3.21.0-cp36-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:52e23a0a6e61691134aa8c8beba89de420602541afaae70f66e16060fdcd677e"}, + {file = "pycryptodomex-3.21.0-cp36-abi3-win32.whl", hash = "sha256:a3d77919e6ff56d89aada1bd009b727b874d464cb0e2e3f00a49f7d2e709d76e"}, + {file = "pycryptodomex-3.21.0-cp36-abi3-win_amd64.whl", hash = "sha256:b0e9765f93fe4890f39875e6c90c96cb341767833cfa767f41b490b506fa9ec0"}, + {file = "pycryptodomex-3.21.0-pp27-pypy_73-manylinux2010_x86_64.whl", hash = "sha256:feaecdce4e5c0045e7a287de0c4351284391fe170729aa9182f6bd967631b3a8"}, + {file = "pycryptodomex-3.21.0-pp27-pypy_73-win32.whl", hash = "sha256:365aa5a66d52fd1f9e0530ea97f392c48c409c2f01ff8b9a39c73ed6f527d36c"}, + {file = "pycryptodomex-3.21.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:3efddfc50ac0ca143364042324046800c126a1d63816d532f2e19e6f2d8c0c31"}, + {file = "pycryptodomex-3.21.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0df2608682db8279a9ebbaf05a72f62a321433522ed0e499bc486a6889b96bf3"}, + {file = "pycryptodomex-3.21.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5823d03e904ea3e53aebd6799d6b8ec63b7675b5d2f4a4bd5e3adcb512d03b37"}, + {file = "pycryptodomex-3.21.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:27e84eeff24250ffec32722334749ac2a57a5fd60332cd6a0680090e7c42877e"}, + {file = "pycryptodomex-3.21.0-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:8ef436cdeea794015263853311f84c1ff0341b98fc7908e8a70595a68cefd971"}, + {file = "pycryptodomex-3.21.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7a1058e6dfe827f4209c5cae466e67610bcd0d66f2f037465daa2a29d92d952b"}, + {file = "pycryptodomex-3.21.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9ba09a5b407cbb3bcb325221e346a140605714b5e880741dc9a1e9ecf1688d42"}, + {file = "pycryptodomex-3.21.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:8a9d8342cf22b74a746e3c6c9453cb0cfbb55943410e3a2619bd9164b48dc9d9"}, + {file = "pycryptodomex-3.21.0.tar.gz", hash = "sha256:222d0bd05381dd25c32dd6065c071ebf084212ab79bab4599ba9e6a3e0009e6c"}, ] [[package]] @@ -2712,17 +2467,6 @@ files = [ {file = "pydeep2-0.5.1.tar.gz", hash = "sha256:44ce447e3253a69d3393f3cc53e3a87a48fe3ff9861793736a7bc218a1b95d77"}, ] -[[package]] -name = "pyelftools" -version = "0.31" -description = "Library for analyzing ELF files and DWARF debugging information" -optional = false -python-versions = "*" -files = [ - {file = "pyelftools-0.31-py3-none-any.whl", hash = "sha256:f52de7b3c7e8c64c8abc04a79a1cf37ac5fb0b8a49809827130b858944840607"}, - {file = "pyelftools-0.31.tar.gz", hash = "sha256:c774416b10310156879443b81187d182d8d9ee499660380e645918b50bc88f99"}, -] - [[package]] name = "pygal" version = "2.4.0" @@ -2791,70 +2535,70 @@ tests = ["coverage[toml] (==5.0.4)", "pytest (>=6.0.0,<7.0.0)"] [[package]] name = "pymongo" -version = "4.9.1" +version = "4.10.1" description = "Python driver for MongoDB " optional = false python-versions = ">=3.8" files = [ - {file = "pymongo-4.9.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:dc3d070d746ab79e9b393a5c236df20e56607389af2b79bf1bfe9a841117558e"}, - {file = "pymongo-4.9.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:fe709d05654c12fc513617c8d5c8d05b7e9cf1d5d94ada68add4e89530c867d2"}, - {file = "pymongo-4.9.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aa4493f304b33c5d2ecee3055c98889ac6724d56f5f922d47420a45d0d4099c9"}, - {file = "pymongo-4.9.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f8e8b8deba6a4bff3dd5421071083219521c74d2acae0322de5c06f1a66c56af"}, - {file = "pymongo-4.9.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e3645aff8419ca60f9ccd08966b2f6b0d78053f9f98a814d025426f1d874c19a"}, - {file = "pymongo-4.9.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:51dbc6251c6783dfcc7d657c346986d8bad7210989b2fe15de16db5204a8e7ae"}, - {file = "pymongo-4.9.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1d7aa9cc2d92e73bdb036c578ba019da94ea165eb147e691cd910a6fab7ce3b7"}, - {file = "pymongo-4.9.1-cp310-cp310-win32.whl", hash = "sha256:8b632e01617f2608880f7b9926f54a5f5ebb51631996e0540fff7fc7980663c9"}, - {file = "pymongo-4.9.1-cp310-cp310-win_amd64.whl", hash = "sha256:f05e34d401be871d7c87cb10727d49315444e4ded07ff876a595e4c23b7436da"}, - {file = "pymongo-4.9.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6bb3d5282278594753089dc7da48bfae4a7f337a2dd4d397eabb591c649e58d0"}, - {file = "pymongo-4.9.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:8f0d5258bc85a4e6b5bcae8160628168e71ec4625a58ceb53327c3280a0b6914"}, - {file = "pymongo-4.9.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:96462fb2175f740701d229f52018ea6e4adc4148c4112e6628bb359dd534a3df"}, - {file = "pymongo-4.9.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:286fb275267f0293364ba579f6354452599161f1902ad411061c7f744ab88328"}, - {file = "pymongo-4.9.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4cddb51cead9700c4dccc916952bc0321b8d766bf782d374bfa0e93ef47c1d20"}, - {file = "pymongo-4.9.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1d79f20f9c7cbc1c708fb80b648b6fbd3220fd3437a9bd6017c1eb592e03b361"}, - {file = "pymongo-4.9.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dd3352eaf578f8e9bdea7a5692910eedad1e8680f60726fc70e99c8af51a5449"}, - {file = "pymongo-4.9.1-cp311-cp311-win32.whl", hash = "sha256:ea3f0196e7c311b9944a609ac175bd91ab97952164a1246716fdd38d53ca3bcc"}, - {file = "pymongo-4.9.1-cp311-cp311-win_amd64.whl", hash = "sha256:b4c793db8457c856f333f396798470b9bfe405e17c307d581532c74cec70150c"}, - {file = "pymongo-4.9.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:47b4896544095d172c366dd4d4ea1da6b0ab1a77d8416897cc1801e2421b1e67"}, - {file = "pymongo-4.9.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:fbb1c7dfcf6c44e9e1928290631c7603817991cdf570691c9e15fca594918435"}, - {file = "pymongo-4.9.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a7689da1d1b444284e4ea9ab2eb64a15307b6b795918c0f3cd7774dd1d8a7556"}, - {file = "pymongo-4.9.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7f962d74201c772555f7a78792fed820a5ea76db5c7ee6cf43748e411b44e430"}, - {file = "pymongo-4.9.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:08fbab69f3fb6f8088c81f4c4a8abd84a99c132034f5e27e47f894bbcb6bf439"}, - {file = "pymongo-4.9.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4327c0d9bd616b8289691360f2d4a09a72fe35479795832eae0d4ff78af53923"}, - {file = "pymongo-4.9.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:34e4993ae78be56f9e27a141168a1ab78253576fa3e893fa335a719ce204c3ef"}, - {file = "pymongo-4.9.1-cp312-cp312-win32.whl", hash = "sha256:e1f346811d4a2369f88ab7a6f886fa9c3bbc9ed4e4f4a3becca8717a73d465cb"}, - {file = "pymongo-4.9.1-cp312-cp312-win_amd64.whl", hash = "sha256:a2b12c74cfd90147babb77f9728646bcedfdbd2bd2a5b4130a00e3a0af1a3d34"}, - {file = "pymongo-4.9.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:a40ea8bc9cffb61c5c9c426c430d22235e085e610ee81ae075ddf51f12f76236"}, - {file = "pymongo-4.9.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:75d5974f874acdb2f125bdbe785045b23a39ecce1d3143dd5712800c7b6d25eb"}, - {file = "pymongo-4.9.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f23a046531030318622414f21198e232cf93c5640da9a80b45596a059c8cc090"}, - {file = "pymongo-4.9.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:91b1a92214c3912af5467f77c2f6435cd76f6de64c70cba7bb4ee43eba7f459e"}, - {file = "pymongo-4.9.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3a846423c4535428f69a90a1451df3718bc59f0c4ab685b9e96d3071951e0be4"}, - {file = "pymongo-4.9.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d476d91a5c9e6c37bc8ec3fb294e1c01d95736ccf01a59bb1540fe2f710f826e"}, - {file = "pymongo-4.9.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:172d8ba0f567e351a18765db23dab7dbcfdffd91a8788d90d46b350f80a40781"}, - {file = "pymongo-4.9.1-cp313-cp313-win32.whl", hash = "sha256:95418e334629440f70fe5ceeefc6cbbd50defb566901c8d68179ffbaec8d5f01"}, - {file = "pymongo-4.9.1-cp313-cp313-win_amd64.whl", hash = "sha256:1dfd2aa30174d36a3ef1dae4ee4c89710c2d65cac52ce6e13f17c710edbd61cf"}, - {file = "pymongo-4.9.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:c4204fad54830a3173a5c939cd052d0561fba03dba7e0ff6852fd631f3314aa4"}, - {file = "pymongo-4.9.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:375765ec81b1f0a26d08928afea0c3dff897c36080a090be53fc7b70cc51d497"}, - {file = "pymongo-4.9.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4d1b959a3dda0775d9111622ee47ad47772aed3a9da2e7d5f2f513fa68175dea"}, - {file = "pymongo-4.9.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:42c19d2b094cdd0ead7dbb38860bbe8268c140334ce55d8b39204ddb4ebd4904"}, - {file = "pymongo-4.9.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1fac1def9e9073f1c80198c99f0ec39c2528236c8912d96d7fd3b0237f4c523a"}, - {file = "pymongo-4.9.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b347052d510989d1f52b8553b31297f21cf74bd9f6aed71ee84e563492f4ff17"}, - {file = "pymongo-4.9.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1b4b961fce213f2bcdc92268f85111a3668c61b9b4d4e7ece27dce3a137cfcbd"}, - {file = "pymongo-4.9.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a0b10cf51ec14a487c94709d294c00e1fb6a0a4c38cdc3acfb2ced5ef60972a0"}, - {file = "pymongo-4.9.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:679b8d55854da7c7fdb82aa5e092ab4de0144daf6758defed8ab00ff9ce05360"}, - {file = "pymongo-4.9.1-cp38-cp38-win32.whl", hash = "sha256:432ad395d2233056b042ccc73234e7136aa65d944d6bd8b5138394bd38aaff79"}, - {file = "pymongo-4.9.1-cp38-cp38-win_amd64.whl", hash = "sha256:9fbe9fad27619ac4cfda5df0ade26a99906da7dfe7b01deddc25997eb1804e4c"}, - {file = "pymongo-4.9.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:99b611ff75b5d9e17183dcf9584a7b04f9db07e51a162f23ea05e485e0735c0a"}, - {file = "pymongo-4.9.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:8089003a99127f917bdbeec177d41cef019cda8ec70534c1018cb60aacd23c2a"}, - {file = "pymongo-4.9.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9d78adf25967c06298c7e488f4cfab79a390fc32c2b1d428613976f99031603d"}, - {file = "pymongo-4.9.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:56877cfcdf7dfc5c6408e4551ec0d6d65ebbca4d744a0bc90400f09ef6bbcc8a"}, - {file = "pymongo-4.9.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:16d2efe559d0d96bc0b74b3ff76701ad6f6e1a65f6581b573dcacc29158131c8"}, - {file = "pymongo-4.9.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f838f613e74b4dad8ace0d90f42346005bece4eda5bf6d389cfadb8322d39316"}, - {file = "pymongo-4.9.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:db5b299e11284f8d82ce2983d8e19fcc28f98f902a179709ef1982b4cca6f8b8"}, - {file = "pymongo-4.9.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b23211c031b45d0f32de83ab7d77f9c26f1025c2d2c91463a5d8594a16103655"}, - {file = "pymongo-4.9.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:687cf70e096381bc65b4273a6a9319617618f7ace65caffc356e1099c4a68511"}, - {file = "pymongo-4.9.1-cp39-cp39-win32.whl", hash = "sha256:e02b03e3815b80a63e773e4c32aed3cf5633d406f376477be74550295c211256"}, - {file = "pymongo-4.9.1-cp39-cp39-win_amd64.whl", hash = "sha256:0492ef43f3342354cf581712e431621c221f60c877ebded84e3f3e53b71bbbe0"}, - {file = "pymongo-4.9.1.tar.gz", hash = "sha256:b7f2d34390acf60e229c30037d1473fcf69f4536cd7f48f6f78c0c931c61c505"}, + {file = "pymongo-4.10.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e699aa68c4a7dea2ab5a27067f7d3e08555f8d2c0dc6a0c8c60cfd9ff2e6a4b1"}, + {file = "pymongo-4.10.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:70645abc714f06b4ad6b72d5bf73792eaad14e3a2cfe29c62a9c81ada69d9e4b"}, + {file = "pymongo-4.10.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ae2fd94c9fe048c94838badcc6e992d033cb9473eb31e5710b3707cba5e8aee2"}, + {file = "pymongo-4.10.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5ded27a4a5374dae03a92e084a60cdbcecd595306555bda553b833baf3fc4868"}, + {file = "pymongo-4.10.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1ecc2455e3974a6c429687b395a0bc59636f2d6aedf5785098cf4e1f180f1c71"}, + {file = "pymongo-4.10.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a920fee41f7d0259f5f72c1f1eb331bc26ffbdc952846f9bd8c3b119013bb52c"}, + {file = "pymongo-4.10.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e0a15665b2d6cf364f4cd114d62452ce01d71abfbd9c564ba8c74dcd7bbd6822"}, + {file = "pymongo-4.10.1-cp310-cp310-win32.whl", hash = "sha256:29e1c323c28a4584b7095378ff046815e39ff82cdb8dc4cc6dfe3acf6f9ad1f8"}, + {file = "pymongo-4.10.1-cp310-cp310-win_amd64.whl", hash = "sha256:88dc4aa45f8744ccfb45164aedb9a4179c93567bbd98a33109d7dc400b00eb08"}, + {file = "pymongo-4.10.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:57ee6becae534e6d47848c97f6a6dff69e3cce7c70648d6049bd586764febe59"}, + {file = "pymongo-4.10.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:6f437a612f4d4f7aca1812311b1e84477145e950fdafe3285b687ab8c52541f3"}, + {file = "pymongo-4.10.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1a970fd3117ab40a4001c3dad333bbf3c43687d90f35287a6237149b5ccae61d"}, + {file = "pymongo-4.10.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7c4d0e7cd08ef9f8fbf2d15ba281ed55604368a32752e476250724c3ce36c72e"}, + {file = "pymongo-4.10.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ca6f700cff6833de4872a4e738f43123db34400173558b558ae079b5535857a4"}, + {file = "pymongo-4.10.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cec237c305fcbeef75c0bcbe9d223d1e22a6e3ba1b53b2f0b79d3d29c742b45b"}, + {file = "pymongo-4.10.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b3337804ea0394a06e916add4e5fac1c89902f1b6f33936074a12505cab4ff05"}, + {file = "pymongo-4.10.1-cp311-cp311-win32.whl", hash = "sha256:778ac646ce6ac1e469664062dfe9ae1f5c9961f7790682809f5ec3b8fda29d65"}, + {file = "pymongo-4.10.1-cp311-cp311-win_amd64.whl", hash = "sha256:9df4ab5594fdd208dcba81be815fa8a8a5d8dedaf3b346cbf8b61c7296246a7a"}, + {file = "pymongo-4.10.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:fbedc4617faa0edf423621bb0b3b8707836687161210d470e69a4184be9ca011"}, + {file = "pymongo-4.10.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7bd26b2aec8ceeb95a5d948d5cc0f62b0eb6d66f3f4230705c1e3d3d2c04ec76"}, + {file = "pymongo-4.10.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fb104c3c2a78d9d85571c8ac90ec4f95bca9b297c6eee5ada71fabf1129e1674"}, + {file = "pymongo-4.10.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4924355245a9c79f77b5cda2db36e0f75ece5faf9f84d16014c0a297f6d66786"}, + {file = "pymongo-4.10.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:11280809e5dacaef4971113f0b4ff4696ee94cfdb720019ff4fa4f9635138252"}, + {file = "pymongo-4.10.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e5d55f2a82e5eb23795f724991cac2bffbb1c0f219c0ba3bf73a835f97f1bb2e"}, + {file = "pymongo-4.10.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e974ab16a60be71a8dfad4e5afccf8dd05d41c758060f5d5bda9a758605d9a5d"}, + {file = "pymongo-4.10.1-cp312-cp312-win32.whl", hash = "sha256:544890085d9641f271d4f7a47684450ed4a7344d6b72d5968bfae32203b1bb7c"}, + {file = "pymongo-4.10.1-cp312-cp312-win_amd64.whl", hash = "sha256:dcc07b1277e8b4bf4d7382ca133850e323b7ab048b8353af496d050671c7ac52"}, + {file = "pymongo-4.10.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:90bc6912948dfc8c363f4ead54d54a02a15a7fee6cfafb36dc450fc8962d2cb7"}, + {file = "pymongo-4.10.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:594dd721b81f301f33e843453638e02d92f63c198358e5a0fa8b8d0b1218dabc"}, + {file = "pymongo-4.10.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0783e0c8e95397c84e9cf8ab092ab1e5dd7c769aec0ef3a5838ae7173b98dea0"}, + {file = "pymongo-4.10.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6fb6a72e88df46d1c1040fd32cd2d2c5e58722e5d3e31060a0393f04ad3283de"}, + {file = "pymongo-4.10.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2e3a593333e20c87415420a4fb76c00b7aae49b6361d2e2205b6fece0563bf40"}, + {file = "pymongo-4.10.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:72e2ace7456167c71cfeca7dcb47bd5dceda7db2231265b80fc625c5e8073186"}, + {file = "pymongo-4.10.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8ad05eb9c97e4f589ed9e74a00fcaac0d443ccd14f38d1258eb4c39a35dd722b"}, + {file = "pymongo-4.10.1-cp313-cp313-win32.whl", hash = "sha256:ee4c86d8e6872a61f7888fc96577b0ea165eb3bdb0d841962b444fa36001e2bb"}, + {file = "pymongo-4.10.1-cp313-cp313-win_amd64.whl", hash = "sha256:45ee87a4e12337353242bc758accc7fb47a2f2d9ecc0382a61e64c8f01e86708"}, + {file = "pymongo-4.10.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:442ca247f53ad24870a01e80a71cd81b3f2318655fd9d66748ee2bd1b1569d9e"}, + {file = "pymongo-4.10.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:23e1d62df5592518204943b507be7b457fb8a4ad95a349440406fd42db5d0923"}, + {file = "pymongo-4.10.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6131bc6568b26e7495a9f3ef2b1700566b76bbecd919f4472bfe90038a61f425"}, + {file = "pymongo-4.10.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fdeba88c540c9ed0338c0b2062d9f81af42b18d6646b3e6dda05cf6edd46ada9"}, + {file = "pymongo-4.10.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:15a624d752dd3c89d10deb0ef6431559b6d074703cab90a70bb849ece02adc6b"}, + {file = "pymongo-4.10.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba164e73fdade9b4614a2497321c5b7512ddf749ed508950bdecc28d8d76a2d9"}, + {file = "pymongo-4.10.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9235fa319993405ae5505bf1333366388add2e06848db7b3deee8f990b69808e"}, + {file = "pymongo-4.10.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e4a65567bd17d19f03157c7ec992c6530eafd8191a4e5ede25566792c4fe3fa2"}, + {file = "pymongo-4.10.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:f1945d48fb9b8a87d515da07f37e5b2c35b364a435f534c122e92747881f4a7c"}, + {file = "pymongo-4.10.1-cp38-cp38-win32.whl", hash = "sha256:345f8d340802ebce509f49d5833cc913da40c82f2e0daf9f60149cacc9ca680f"}, + {file = "pymongo-4.10.1-cp38-cp38-win_amd64.whl", hash = "sha256:3a70d5efdc0387ac8cd50f9a5f379648ecfc322d14ec9e1ba8ec957e5d08c372"}, + {file = "pymongo-4.10.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:15b1492cc5c7cd260229590be7218261e81684b8da6d6de2660cf743445500ce"}, + {file = "pymongo-4.10.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:95207503c41b97e7ecc7e596d84a61f441b4935f11aa8332828a754e7ada8c82"}, + {file = "pymongo-4.10.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bb99f003c720c6d83be02c8f1a7787c22384a8ca9a4181e406174db47a048619"}, + {file = "pymongo-4.10.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f2bc1ee4b1ca2c4e7e6b7a5e892126335ec8d9215bcd3ac2fe075870fefc3358"}, + {file = "pymongo-4.10.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:93a0833c10a967effcd823b4e7445ec491f0bf6da5de0ca33629c0528f42b748"}, + {file = "pymongo-4.10.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0f56707497323150bd2ed5d63067f4ffce940d0549d4ea2dfae180deec7f9363"}, + {file = "pymongo-4.10.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:409ab7d6c4223e5c85881697f365239dd3ed1b58f28e4124b846d9d488c86880"}, + {file = "pymongo-4.10.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:dac78a650dc0637d610905fd06b5fa6419ae9028cf4d04d6a2657bc18a66bbce"}, + {file = "pymongo-4.10.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:1ec3fa88b541e0481aff3c35194c9fac96e4d57ec5d1c122376000eb28c01431"}, + {file = "pymongo-4.10.1-cp39-cp39-win32.whl", hash = "sha256:e0e961923a7b8a1c801c43552dcb8153e45afa41749d9efbd3a6d33f45489f7a"}, + {file = "pymongo-4.10.1-cp39-cp39-win_amd64.whl", hash = "sha256:dabe8bf1ad644e6b93f3acf90ff18536d94538ca4d27e583c6db49889e98e48f"}, + {file = "pymongo-4.10.1.tar.gz", hash = "sha256:a9de02be53b6bb98efe0b9eda84ffa1ec027fcb23a2de62c4f941d9a2f2f3330"}, ] [package.dependencies] @@ -3109,58 +2853,6 @@ files = [ [package.extras] cli = ["click (>=5.0)"] -[[package]] -name = "python-flirt" -version = "0.8.10" -description = "A Python library for parsing, compiling, and matching Fast Library Identification and Recognition Technology (FLIRT) signatures." -optional = false -python-versions = ">=3.8" -files = [ - {file = "python_flirt-0.8.10-cp310-cp310-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:6c3185790d3f3749ea2cb984f10259d533ad54036b5878cedcd4149ce3122d5e"}, - {file = "python_flirt-0.8.10-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:0db5c5d9a8920cdb32fd1dbff8fe00e99d32fd9d478b15317093e23942c0aef6"}, - {file = "python_flirt-0.8.10-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:9b5a285ea80a63d68af56fb406de5ab263ab1b6c988def94c76ebe91d1e9eeec"}, - {file = "python_flirt-0.8.10-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5d3172c9ac87d36add8eb15d42f33636d408516c7e4834dd572836ef5f4e9e26"}, - {file = "python_flirt-0.8.10-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:cc1b020e54f119916f7cdac4a24f692643915af83d51e2f73f35472da16213ac"}, - {file = "python_flirt-0.8.10-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b17592ac73c49515f4c7ae4945060dea18685bdfb320f0bbcd0f613d11492dbb"}, - {file = "python_flirt-0.8.10-cp310-none-win32.whl", hash = "sha256:b927124c042863d7d488c3b64796c6c690252f1b4f9cbe1135681c6918e53d99"}, - {file = "python_flirt-0.8.10-cp310-none-win_amd64.whl", hash = "sha256:2d8ab2d51b26502415a7a3cd82eb825252be508d7f32d870440fd1096b444232"}, - {file = "python_flirt-0.8.10-cp311-cp311-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:166d27e034118562aa95d7b403a5b111d5ba8469fe14dd4077b081bee7266d00"}, - {file = "python_flirt-0.8.10-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:354814081fcba58f5448ef8bd3b3a7814cce2cb1ed7ad9c1d572447bc85f9e7a"}, - {file = "python_flirt-0.8.10-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:055412a990b471acc2ce16d9372e4a1af379a81bc54bedd864d35f5f63c8b010"}, - {file = "python_flirt-0.8.10-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8da95d051a6bbcebb3043541adfb3dd635b792a837e8ac829c017549ba00d977"}, - {file = "python_flirt-0.8.10-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c14ff6b3a9dd1d0629d247688e8e69d348dab9df2f654b0f2424343f66446ce5"}, - {file = "python_flirt-0.8.10-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2547d34b146ab18bf64c1eceb46be0643d903bbf396aabe79d07ed8475893cea"}, - {file = "python_flirt-0.8.10-cp311-none-win32.whl", hash = "sha256:a59b5c26a12038484ece6bb66eb2e45c286fe476f5a4bed5e8f4e5dabba63991"}, - {file = "python_flirt-0.8.10-cp311-none-win_amd64.whl", hash = "sha256:4fb8d48f304ef6394dee74a5d6b1e31f9b91bc046305ea6ee1f26d8e28229cb4"}, - {file = "python_flirt-0.8.10-cp312-cp312-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:a19cbf0a2c87decb8d861b74a499eb4b3fd6fc65ac73227d6330641a5d070c6c"}, - {file = "python_flirt-0.8.10-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:2b0e285a582576c2ddba9af17a97fbfdd52187fbf098a797df9e00034000796d"}, - {file = "python_flirt-0.8.10-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:b9bb40cb897458ac0d9af121e35aa28ea33ea1a9eadf33bbf79ff84a81f2eaf4"}, - {file = "python_flirt-0.8.10-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:30960a682673bb25ae2bd8ba7c754e9e18faa4427fe75fe29d5fc341fa974346"}, - {file = "python_flirt-0.8.10-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:4bfe6e2b8eb0e587476fab7db21a15fb40e96e944f404e872c906d89450a52bc"}, - {file = "python_flirt-0.8.10-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:02792127c579d624a98c8f65a1b6f2b27c2d8be673a4ae3e26d9b42543051cf3"}, - {file = "python_flirt-0.8.10-cp312-none-win32.whl", hash = "sha256:fc7e6041c7e146328a6daf05303590aa18251c0e5cf92f8b93e8f1eafaadb7a7"}, - {file = "python_flirt-0.8.10-cp312-none-win_amd64.whl", hash = "sha256:f21d7e23a82ba6cfcde4fc252cd998af8848b7e5bbd7b8c670384073d3b7ad66"}, - {file = "python_flirt-0.8.10-cp38-cp38-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:38e96fdf79b6e4b6b86b37d33278c8522eb41972a17d98d8924d3772c527ecd8"}, - {file = "python_flirt-0.8.10-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:ce6f443bec1ac970e41c8238e945b6f08af402bab32256c6b818143acd0a86d6"}, - {file = "python_flirt-0.8.10-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:19e38ea51af68113d88e180c339873d202bef8637532a2c9173dbac38ff4aece"}, - {file = "python_flirt-0.8.10-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d0102bfdda68ce2050cfb61cd2e8bbc8225bc2b5a0535fb492e12c42d9dbf23a"}, - {file = "python_flirt-0.8.10-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:547fc7d8567db0332b229be0551c3aa65c839d439fdd317b7184edb491dde322"}, - {file = "python_flirt-0.8.10-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:877a99236e7e37f4e94f223297e9029ab14426a4d4d5f7a621a1719b0375dda1"}, - {file = "python_flirt-0.8.10-cp38-none-win32.whl", hash = "sha256:cb173f1030cd05f586f20b68c594bdc54f745d4fb12dc8db100dc70127a771d7"}, - {file = "python_flirt-0.8.10-cp38-none-win_amd64.whl", hash = "sha256:2f4cebbf3cba105f5f0db64a030109c966f4aecb29f94c7ac6e4594f3d4b3c63"}, - {file = "python_flirt-0.8.10-cp39-cp39-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:c1f8e406d15f31049ff558534b4be952fb073aadc2e7174e650f4a71256282c6"}, - {file = "python_flirt-0.8.10-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:82b820c27a4f8f94804aa42617e8d5cb80e76ca55bd89b656ff3924dae8af293"}, - {file = "python_flirt-0.8.10-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:acedddf5acd384626c55b7ed2bda71a5651eb7aed3be1d7098507ea0d3adaabb"}, - {file = "python_flirt-0.8.10-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6745709e936c19100190c52220adda8290dd6bad31d8f708cf3c52deb87546d9"}, - {file = "python_flirt-0.8.10-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:6897be2d12fed520524259640648f5022c3c1bff2bf2da10f018315823cc4134"}, - {file = "python_flirt-0.8.10-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0d2f444799bc2b73271fb6e0715f9ccb831308999051ca58f121282499a955b1"}, - {file = "python_flirt-0.8.10-cp39-none-win32.whl", hash = "sha256:729002c7a6a15905a8dd60b646d5a28605ca73ed8a62886caaf3a49cfeb5a7bf"}, - {file = "python_flirt-0.8.10-cp39-none-win_amd64.whl", hash = "sha256:0b79ee2a6b0a098225510ab5cc0d54f1534ecfd4c647b3a614ce9dca9615d13a"}, -] - -[package.extras] -dev = ["black (==22.10.0)", "isort (==5.10.1)", "maturin", "mypy (==0.982)", "pycodestyle (==2.9.1)", "pytest (==7.1.3)", "pytest-cov (==4.0.0)", "pytest-instafail (==0.4.2)", "pytest-sugar (==0.9.4)"] - [[package]] name = "python-magic" version = "0.4.27" @@ -3305,12 +2997,14 @@ pycryptodomex = "*" [[package]] name = "rat-king-parser" -version = "3.0.0" +version = "3.1.3" description = "A robust, multiprocessing-capable, multi-family RAT config parser/config extractor for AsyncRAT, DcRAT, VenomRAT, QuasarRAT, XWorm, Xeno RAT, and cloned/derivative RAT families." optional = false python-versions = ">=3.10" -files = [] -develop = false +files = [ + {file = "rat_king_parser-3.1.3-py3-none-any.whl", hash = "sha256:229c7d4565e7c0ea3e6a75a8252df9223286a26b77b2d449c2612b95c8406605"}, + {file = "rat_king_parser-3.1.3.tar.gz", hash = "sha256:cd662eb127c1bb85345a4460439608cfc87b82e833503b632d5ccc713eb49123"}, +] [package.dependencies] cryptography = "*" @@ -3320,76 +3014,107 @@ yara-python = "*" [package.extras] maco = ["maco", "validators"] -[package.source] -type = "git" -url = "https://github.com/jeFF0Falltrades/rat_king_parser" -reference = "ab849ec8face38c8dac3f803ae5fe7cf8be26583" -resolved_reference = "ab849ec8face38c8dac3f803ae5fe7cf8be26583" - [[package]] name = "regex" -version = "2021.7.6" +version = "2024.9.11" description = "Alternative regular expression module, to replace re." optional = false -python-versions = "*" +python-versions = ">=3.8" files = [ - {file = "regex-2021.7.6-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:e6a1e5ca97d411a461041d057348e578dc344ecd2add3555aedba3b408c9f874"}, - {file = "regex-2021.7.6-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:6afe6a627888c9a6cfbb603d1d017ce204cebd589d66e0703309b8048c3b0854"}, - {file = "regex-2021.7.6-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:ccb3d2190476d00414aab36cca453e4596e8f70a206e2aa8db3d495a109153d2"}, - {file = "regex-2021.7.6-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:ed693137a9187052fc46eedfafdcb74e09917166362af4cc4fddc3b31560e93d"}, - {file = "regex-2021.7.6-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:99d8ab206a5270c1002bfcf25c51bf329ca951e5a169f3b43214fdda1f0b5f0d"}, - {file = "regex-2021.7.6-cp36-cp36m-manylinux2014_i686.whl", hash = "sha256:b85ac458354165405c8a84725de7bbd07b00d9f72c31a60ffbf96bb38d3e25fa"}, - {file = "regex-2021.7.6-cp36-cp36m-manylinux2014_x86_64.whl", hash = "sha256:3f5716923d3d0bfb27048242a6e0f14eecdb2e2a7fac47eda1d055288595f222"}, - {file = "regex-2021.7.6-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e5983c19d0beb6af88cb4d47afb92d96751fb3fa1784d8785b1cdf14c6519407"}, - {file = "regex-2021.7.6-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bf1d2d183abc7faa101ebe0b8d04fd19cb9138820abc8589083035c9440b8ca6"}, - {file = "regex-2021.7.6-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:1947e7de155063e1c495c50590229fb98720d4c383af5031bbcb413db33fa1be"}, - {file = "regex-2021.7.6-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:17d8a3f99b18d87ac54a449b836d485cc8c195bb6f5e4379c84c8519045facc9"}, - {file = "regex-2021.7.6-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:d30895ec80cc80358392841add9dde81ea1d54a4949049269115e6b0555d0498"}, - {file = "regex-2021.7.6-cp36-cp36m-win32.whl", hash = "sha256:c92831dac113a6e0ab28bc98f33781383fe294df1a2c3dfd1e850114da35fd5b"}, - {file = "regex-2021.7.6-cp36-cp36m-win_amd64.whl", hash = "sha256:791aa1b300e5b6e5d597c37c346fb4d66422178566bbb426dd87eaae475053fb"}, - {file = "regex-2021.7.6-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:59506c6e8bd9306cd8a41511e32d16d5d1194110b8cfe5a11d102d8b63cf945d"}, - {file = "regex-2021.7.6-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:564a4c8a29435d1f2256ba247a0315325ea63335508ad8ed938a4f14c4116a5d"}, - {file = "regex-2021.7.6-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:59c00bb8dd8775473cbfb967925ad2c3ecc8886b3b2d0c90a8e2707e06c743f0"}, - {file = "regex-2021.7.6-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:9a854b916806c7e3b40e6616ac9e85d3cdb7649d9e6590653deb5b341a736cec"}, - {file = "regex-2021.7.6-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:db2b7df831c3187a37f3bb80ec095f249fa276dbe09abd3d35297fc250385694"}, - {file = "regex-2021.7.6-cp37-cp37m-manylinux2014_i686.whl", hash = "sha256:173bc44ff95bc1e96398c38f3629d86fa72e539c79900283afa895694229fe6a"}, - {file = "regex-2021.7.6-cp37-cp37m-manylinux2014_x86_64.whl", hash = "sha256:15dddb19823f5147e7517bb12635b3c82e6f2a3a6b696cc3e321522e8b9308ad"}, - {file = "regex-2021.7.6-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2ddeabc7652024803666ea09f32dd1ed40a0579b6fbb2a213eba590683025895"}, - {file = "regex-2021.7.6-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8244c681018423a0d1784bc6b9af33bdf55f2ab8acb1f3cd9dd83d90e0813253"}, - {file = "regex-2021.7.6-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:8a4c742089faf0e51469c6a1ad7e3d3d21afae54a16a6cead85209dfe0a1ce65"}, - {file = "regex-2021.7.6-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:914e626dc8e75fe4fc9b7214763f141d9f40165d00dfe680b104fa1b24063bbf"}, - {file = "regex-2021.7.6-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:3fabb19c82ecf39832a3f5060dfea9a7ab270ef156039a1143a29a83a09a62de"}, - {file = "regex-2021.7.6-cp37-cp37m-win32.whl", hash = "sha256:f080248b3e029d052bf74a897b9d74cfb7643537fbde97fe8225a6467fb559b5"}, - {file = "regex-2021.7.6-cp37-cp37m-win_amd64.whl", hash = "sha256:d8bbce0c96462dbceaa7ac4a7dfbbee92745b801b24bce10a98d2f2b1ea9432f"}, - {file = "regex-2021.7.6-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:edd1a68f79b89b0c57339bce297ad5d5ffcc6ae7e1afdb10f1947706ed066c9c"}, - {file = "regex-2021.7.6-cp38-cp38-manylinux1_i686.whl", hash = "sha256:422dec1e7cbb2efbbe50e3f1de36b82906def93ed48da12d1714cabcd993d7f0"}, - {file = "regex-2021.7.6-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:cbe23b323988a04c3e5b0c387fe3f8f363bf06c0680daf775875d979e376bd26"}, - {file = "regex-2021.7.6-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:0eb2c6e0fcec5e0f1d3bcc1133556563222a2ffd2211945d7b1480c1b1a42a6f"}, - {file = "regex-2021.7.6-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:1c78780bf46d620ff4fff40728f98b8afd8b8e35c3efd638c7df67be2d5cddbf"}, - {file = "regex-2021.7.6-cp38-cp38-manylinux2014_i686.whl", hash = "sha256:bc84fb254a875a9f66616ed4538542fb7965db6356f3df571d783f7c8d256edd"}, - {file = "regex-2021.7.6-cp38-cp38-manylinux2014_x86_64.whl", hash = "sha256:598c0a79b4b851b922f504f9f39a863d83ebdfff787261a5ed061c21e67dd761"}, - {file = "regex-2021.7.6-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:875c355360d0f8d3d827e462b29ea7682bf52327d500a4f837e934e9e4656068"}, - {file = "regex-2021.7.6-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dfc0957c4a4b91eff5ad036088769e600a25774256cd0e1154378591ce573f08"}, - {file = "regex-2021.7.6-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:efb4af05fa4d2fc29766bf516f1f5098d6b5c3ed846fde980c18bf8646ad3979"}, - {file = "regex-2021.7.6-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7423aca7cc30a6228ccdcf2ea76f12923d652c5c7c6dc1959a0b004e308f39fb"}, - {file = "regex-2021.7.6-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:bb9834c1e77493efd7343b8e38950dee9797d2d6f2d5fd91c008dfaef64684b9"}, - {file = "regex-2021.7.6-cp38-cp38-win32.whl", hash = "sha256:e586f448df2bbc37dfadccdb7ccd125c62b4348cb90c10840d695592aa1b29e0"}, - {file = "regex-2021.7.6-cp38-cp38-win_amd64.whl", hash = "sha256:2fe5e71e11a54e3355fa272137d521a40aace5d937d08b494bed4529964c19c4"}, - {file = "regex-2021.7.6-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6110bab7eab6566492618540c70edd4d2a18f40ca1d51d704f1d81c52d245026"}, - {file = "regex-2021.7.6-cp39-cp39-manylinux1_i686.whl", hash = "sha256:4f64fc59fd5b10557f6cd0937e1597af022ad9b27d454e182485f1db3008f417"}, - {file = "regex-2021.7.6-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:89e5528803566af4df368df2d6f503c84fbfb8249e6631c7b025fe23e6bd0cde"}, - {file = "regex-2021.7.6-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:2366fe0479ca0e9afa534174faa2beae87847d208d457d200183f28c74eaea59"}, - {file = "regex-2021.7.6-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:f9392a4555f3e4cb45310a65b403d86b589adc773898c25a39184b1ba4db8985"}, - {file = "regex-2021.7.6-cp39-cp39-manylinux2014_i686.whl", hash = "sha256:2bceeb491b38225b1fee4517107b8491ba54fba77cf22a12e996d96a3c55613d"}, - {file = "regex-2021.7.6-cp39-cp39-manylinux2014_x86_64.whl", hash = "sha256:f98dc35ab9a749276f1a4a38ab3e0e2ba1662ce710f6530f5b0a6656f1c32b58"}, - {file = "regex-2021.7.6-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:319eb2a8d0888fa6f1d9177705f341bc9455a2c8aca130016e52c7fe8d6c37a3"}, - {file = "regex-2021.7.6-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:598ee917dbe961dcf827217bf2466bb86e4ee5a8559705af57cbabb3489dd37e"}, - {file = "regex-2021.7.6-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:56fc7045a1999a8d9dd1896715bc5c802dfec5b9b60e883d2cbdecb42adedea4"}, - {file = "regex-2021.7.6-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e8363ac90ea63c3dd0872dfdb695f38aff3334bfa5712cffb238bd3ffef300e3"}, - {file = "regex-2021.7.6-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:716a6db91b3641f566531ffcc03ceec00b2447f0db9942b3c6ea5d2827ad6be3"}, - {file = "regex-2021.7.6-cp39-cp39-win32.whl", hash = "sha256:eaf58b9e30e0e546cdc3ac06cf9165a1ca5b3de8221e9df679416ca667972035"}, - {file = "regex-2021.7.6-cp39-cp39-win_amd64.whl", hash = "sha256:4c9c3155fe74269f61e27617529b7f09552fbb12e44b1189cebbdb24294e6e1c"}, - {file = "regex-2021.7.6.tar.gz", hash = "sha256:8394e266005f2d8c6f0bc6780001f7afa3ef81a7a2111fa35058ded6fce79e4d"}, + {file = "regex-2024.9.11-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:1494fa8725c285a81d01dc8c06b55287a1ee5e0e382d8413adc0a9197aac6408"}, + {file = "regex-2024.9.11-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0e12c481ad92d129c78f13a2a3662317e46ee7ef96c94fd332e1c29131875b7d"}, + {file = "regex-2024.9.11-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:16e13a7929791ac1216afde26f712802e3df7bf0360b32e4914dca3ab8baeea5"}, + {file = "regex-2024.9.11-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:46989629904bad940bbec2106528140a218b4a36bb3042d8406980be1941429c"}, + {file = "regex-2024.9.11-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a906ed5e47a0ce5f04b2c981af1c9acf9e8696066900bf03b9d7879a6f679fc8"}, + {file = "regex-2024.9.11-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e9a091b0550b3b0207784a7d6d0f1a00d1d1c8a11699c1a4d93db3fbefc3ad35"}, + {file = "regex-2024.9.11-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5ddcd9a179c0a6fa8add279a4444015acddcd7f232a49071ae57fa6e278f1f71"}, + {file = "regex-2024.9.11-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6b41e1adc61fa347662b09398e31ad446afadff932a24807d3ceb955ed865cc8"}, + {file = "regex-2024.9.11-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:ced479f601cd2f8ca1fd7b23925a7e0ad512a56d6e9476f79b8f381d9d37090a"}, + {file = "regex-2024.9.11-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:635a1d96665f84b292e401c3d62775851aedc31d4f8784117b3c68c4fcd4118d"}, + {file = "regex-2024.9.11-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:c0256beda696edcf7d97ef16b2a33a8e5a875affd6fa6567b54f7c577b30a137"}, + {file = "regex-2024.9.11-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:3ce4f1185db3fbde8ed8aa223fc9620f276c58de8b0d4f8cc86fd1360829edb6"}, + {file = "regex-2024.9.11-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:09d77559e80dcc9d24570da3745ab859a9cf91953062e4ab126ba9d5993688ca"}, + {file = "regex-2024.9.11-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:7a22ccefd4db3f12b526eccb129390942fe874a3a9fdbdd24cf55773a1faab1a"}, + {file = "regex-2024.9.11-cp310-cp310-win32.whl", hash = "sha256:f745ec09bc1b0bd15cfc73df6fa4f726dcc26bb16c23a03f9e3367d357eeedd0"}, + {file = "regex-2024.9.11-cp310-cp310-win_amd64.whl", hash = "sha256:01c2acb51f8a7d6494c8c5eafe3d8e06d76563d8a8a4643b37e9b2dd8a2ff623"}, + {file = "regex-2024.9.11-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:2cce2449e5927a0bf084d346da6cd5eb016b2beca10d0013ab50e3c226ffc0df"}, + {file = "regex-2024.9.11-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3b37fa423beefa44919e009745ccbf353d8c981516e807995b2bd11c2c77d268"}, + {file = "regex-2024.9.11-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:64ce2799bd75039b480cc0360907c4fb2f50022f030bf9e7a8705b636e408fad"}, + {file = "regex-2024.9.11-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a4cc92bb6db56ab0c1cbd17294e14f5e9224f0cc6521167ef388332604e92679"}, + {file = "regex-2024.9.11-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d05ac6fa06959c4172eccd99a222e1fbf17b5670c4d596cb1e5cde99600674c4"}, + {file = "regex-2024.9.11-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:040562757795eeea356394a7fb13076ad4f99d3c62ab0f8bdfb21f99a1f85664"}, + {file = "regex-2024.9.11-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6113c008a7780792efc80f9dfe10ba0cd043cbf8dc9a76ef757850f51b4edc50"}, + {file = "regex-2024.9.11-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8e5fb5f77c8745a60105403a774fe2c1759b71d3e7b4ca237a5e67ad066c7199"}, + {file = "regex-2024.9.11-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:54d9ff35d4515debf14bc27f1e3b38bfc453eff3220f5bce159642fa762fe5d4"}, + {file = "regex-2024.9.11-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:df5cbb1fbc74a8305b6065d4ade43b993be03dbe0f8b30032cced0d7740994bd"}, + {file = "regex-2024.9.11-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:7fb89ee5d106e4a7a51bce305ac4efb981536301895f7bdcf93ec92ae0d91c7f"}, + {file = "regex-2024.9.11-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:a738b937d512b30bf75995c0159c0ddf9eec0775c9d72ac0202076c72f24aa96"}, + {file = "regex-2024.9.11-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:e28f9faeb14b6f23ac55bfbbfd3643f5c7c18ede093977f1df249f73fd22c7b1"}, + {file = "regex-2024.9.11-cp311-cp311-win32.whl", hash = "sha256:18e707ce6c92d7282dfce370cd205098384b8ee21544e7cb29b8aab955b66fa9"}, + {file = "regex-2024.9.11-cp311-cp311-win_amd64.whl", hash = "sha256:313ea15e5ff2a8cbbad96ccef6be638393041b0a7863183c2d31e0c6116688cf"}, + {file = "regex-2024.9.11-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:b0d0a6c64fcc4ef9c69bd5b3b3626cc3776520a1637d8abaa62b9edc147a58f7"}, + {file = "regex-2024.9.11-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:49b0e06786ea663f933f3710a51e9385ce0cba0ea56b67107fd841a55d56a231"}, + {file = "regex-2024.9.11-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5b513b6997a0b2f10e4fd3a1313568e373926e8c252bd76c960f96fd039cd28d"}, + {file = "regex-2024.9.11-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ee439691d8c23e76f9802c42a95cfeebf9d47cf4ffd06f18489122dbb0a7ad64"}, + {file = "regex-2024.9.11-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a8f877c89719d759e52783f7fe6e1c67121076b87b40542966c02de5503ace42"}, + {file = "regex-2024.9.11-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:23b30c62d0f16827f2ae9f2bb87619bc4fba2044911e2e6c2eb1af0161cdb766"}, + {file = "regex-2024.9.11-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:85ab7824093d8f10d44330fe1e6493f756f252d145323dd17ab6b48733ff6c0a"}, + {file = "regex-2024.9.11-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8dee5b4810a89447151999428fe096977346cf2f29f4d5e29609d2e19e0199c9"}, + {file = "regex-2024.9.11-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:98eeee2f2e63edae2181c886d7911ce502e1292794f4c5ee71e60e23e8d26b5d"}, + {file = "regex-2024.9.11-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:57fdd2e0b2694ce6fc2e5ccf189789c3e2962916fb38779d3e3521ff8fe7a822"}, + {file = "regex-2024.9.11-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:d552c78411f60b1fdaafd117a1fca2f02e562e309223b9d44b7de8be451ec5e0"}, + {file = "regex-2024.9.11-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:a0b2b80321c2ed3fcf0385ec9e51a12253c50f146fddb2abbb10f033fe3d049a"}, + {file = "regex-2024.9.11-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:18406efb2f5a0e57e3a5881cd9354c1512d3bb4f5c45d96d110a66114d84d23a"}, + {file = "regex-2024.9.11-cp312-cp312-win32.whl", hash = "sha256:e464b467f1588e2c42d26814231edecbcfe77f5ac414d92cbf4e7b55b2c2a776"}, + {file = "regex-2024.9.11-cp312-cp312-win_amd64.whl", hash = "sha256:9e8719792ca63c6b8340380352c24dcb8cd7ec49dae36e963742a275dfae6009"}, + {file = "regex-2024.9.11-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:c157bb447303070f256e084668b702073db99bbb61d44f85d811025fcf38f784"}, + {file = "regex-2024.9.11-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:4db21ece84dfeefc5d8a3863f101995de646c6cb0536952c321a2650aa202c36"}, + {file = "regex-2024.9.11-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:220e92a30b426daf23bb67a7962900ed4613589bab80382be09b48896d211e92"}, + {file = "regex-2024.9.11-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eb1ae19e64c14c7ec1995f40bd932448713d3c73509e82d8cd7744dc00e29e86"}, + {file = "regex-2024.9.11-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f47cd43a5bfa48f86925fe26fbdd0a488ff15b62468abb5d2a1e092a4fb10e85"}, + {file = "regex-2024.9.11-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9d4a76b96f398697fe01117093613166e6aa8195d63f1b4ec3f21ab637632963"}, + {file = "regex-2024.9.11-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0ea51dcc0835eea2ea31d66456210a4e01a076d820e9039b04ae8d17ac11dee6"}, + {file = "regex-2024.9.11-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b7aaa315101c6567a9a45d2839322c51c8d6e81f67683d529512f5bcfb99c802"}, + {file = "regex-2024.9.11-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:c57d08ad67aba97af57a7263c2d9006d5c404d721c5f7542f077f109ec2a4a29"}, + {file = "regex-2024.9.11-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:f8404bf61298bb6f8224bb9176c1424548ee1181130818fcd2cbffddc768bed8"}, + {file = "regex-2024.9.11-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:dd4490a33eb909ef5078ab20f5f000087afa2a4daa27b4c072ccb3cb3050ad84"}, + {file = "regex-2024.9.11-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:eee9130eaad130649fd73e5cd92f60e55708952260ede70da64de420cdcad554"}, + {file = "regex-2024.9.11-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6a2644a93da36c784e546de579ec1806bfd2763ef47babc1b03d765fe560c9f8"}, + {file = "regex-2024.9.11-cp313-cp313-win32.whl", hash = "sha256:e997fd30430c57138adc06bba4c7c2968fb13d101e57dd5bb9355bf8ce3fa7e8"}, + {file = "regex-2024.9.11-cp313-cp313-win_amd64.whl", hash = "sha256:042c55879cfeb21a8adacc84ea347721d3d83a159da6acdf1116859e2427c43f"}, + {file = "regex-2024.9.11-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:35f4a6f96aa6cb3f2f7247027b07b15a374f0d5b912c0001418d1d55024d5cb4"}, + {file = "regex-2024.9.11-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:55b96e7ce3a69a8449a66984c268062fbaa0d8ae437b285428e12797baefce7e"}, + {file = "regex-2024.9.11-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:cb130fccd1a37ed894824b8c046321540263013da72745d755f2d35114b81a60"}, + {file = "regex-2024.9.11-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:323c1f04be6b2968944d730e5c2091c8c89767903ecaa135203eec4565ed2b2b"}, + {file = "regex-2024.9.11-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:be1c8ed48c4c4065ecb19d882a0ce1afe0745dfad8ce48c49586b90a55f02366"}, + {file = "regex-2024.9.11-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b5b029322e6e7b94fff16cd120ab35a253236a5f99a79fb04fda7ae71ca20ae8"}, + {file = "regex-2024.9.11-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f6fff13ef6b5f29221d6904aa816c34701462956aa72a77f1f151a8ec4f56aeb"}, + {file = "regex-2024.9.11-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:587d4af3979376652010e400accc30404e6c16b7df574048ab1f581af82065e4"}, + {file = "regex-2024.9.11-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:079400a8269544b955ffa9e31f186f01d96829110a3bf79dc338e9910f794fca"}, + {file = "regex-2024.9.11-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:f9268774428ec173654985ce55fc6caf4c6d11ade0f6f914d48ef4719eb05ebb"}, + {file = "regex-2024.9.11-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:23f9985c8784e544d53fc2930fc1ac1a7319f5d5332d228437acc9f418f2f168"}, + {file = "regex-2024.9.11-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:ae2941333154baff9838e88aa71c1d84f4438189ecc6021a12c7573728b5838e"}, + {file = "regex-2024.9.11-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:e93f1c331ca8e86fe877a48ad64e77882c0c4da0097f2212873a69bbfea95d0c"}, + {file = "regex-2024.9.11-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:846bc79ee753acf93aef4184c040d709940c9d001029ceb7b7a52747b80ed2dd"}, + {file = "regex-2024.9.11-cp38-cp38-win32.whl", hash = "sha256:c94bb0a9f1db10a1d16c00880bdebd5f9faf267273b8f5bd1878126e0fbde771"}, + {file = "regex-2024.9.11-cp38-cp38-win_amd64.whl", hash = "sha256:2b08fce89fbd45664d3df6ad93e554b6c16933ffa9d55cb7e01182baaf971508"}, + {file = "regex-2024.9.11-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:07f45f287469039ffc2c53caf6803cd506eb5f5f637f1d4acb37a738f71dd066"}, + {file = "regex-2024.9.11-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:4838e24ee015101d9f901988001038f7f0d90dc0c3b115541a1365fb439add62"}, + {file = "regex-2024.9.11-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:6edd623bae6a737f10ce853ea076f56f507fd7726bee96a41ee3d68d347e4d16"}, + {file = "regex-2024.9.11-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c69ada171c2d0e97a4b5aa78fbb835e0ffbb6b13fc5da968c09811346564f0d3"}, + {file = "regex-2024.9.11-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:02087ea0a03b4af1ed6ebab2c54d7118127fee8d71b26398e8e4b05b78963199"}, + {file = "regex-2024.9.11-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:69dee6a020693d12a3cf892aba4808fe168d2a4cef368eb9bf74f5398bfd4ee8"}, + {file = "regex-2024.9.11-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:297f54910247508e6e5cae669f2bc308985c60540a4edd1c77203ef19bfa63ca"}, + {file = "regex-2024.9.11-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ecea58b43a67b1b79805f1a0255730edaf5191ecef84dbc4cc85eb30bc8b63b9"}, + {file = "regex-2024.9.11-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:eab4bb380f15e189d1313195b062a6aa908f5bd687a0ceccd47c8211e9cf0d4a"}, + {file = "regex-2024.9.11-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:0cbff728659ce4bbf4c30b2a1be040faafaa9eca6ecde40aaff86f7889f4ab39"}, + {file = "regex-2024.9.11-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:54c4a097b8bc5bb0dfc83ae498061d53ad7b5762e00f4adaa23bee22b012e6ba"}, + {file = "regex-2024.9.11-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:73d6d2f64f4d894c96626a75578b0bf7d9e56dcda8c3d037a2118fdfe9b1c664"}, + {file = "regex-2024.9.11-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:e53b5fbab5d675aec9f0c501274c467c0f9a5d23696cfc94247e1fb56501ed89"}, + {file = "regex-2024.9.11-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:0ffbcf9221e04502fc35e54d1ce9567541979c3fdfb93d2c554f0ca583a19b35"}, + {file = "regex-2024.9.11-cp39-cp39-win32.whl", hash = "sha256:e4c22e1ac1f1ec1e09f72e6c44d8f2244173db7eb9629cc3a346a8d7ccc31142"}, + {file = "regex-2024.9.11-cp39-cp39-win_amd64.whl", hash = "sha256:faa3c142464efec496967359ca99696c896c591c56c53506bac1ad465f66e919"}, + {file = "regex-2024.9.11.tar.gz", hash = "sha256:6c188c307e8433bcb63dc1915022deb553b4203a70722fc542c363bf120a01fd"}, ] [[package]] @@ -3449,99 +3174,23 @@ rsa = ["oauthlib[signedtoken] (>=3.0.0)"] [[package]] name = "rich" -version = "13.8.1" +version = "13.9.4" description = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal" optional = false -python-versions = ">=3.7.0" +python-versions = ">=3.8.0" files = [ - {file = "rich-13.8.1-py3-none-any.whl", hash = "sha256:1760a3c0848469b97b558fc61c85233e3dafb69c7a071b4d60c38099d3cd4c06"}, - {file = "rich-13.8.1.tar.gz", hash = "sha256:8260cda28e3db6bf04d2d1ef4dbc03ba80a824c88b0e7668a0f23126a424844a"}, + {file = "rich-13.9.4-py3-none-any.whl", hash = "sha256:6049d5e6ec054bf2779ab3358186963bac2ea89175919d699e378b99738c2a90"}, + {file = "rich-13.9.4.tar.gz", hash = "sha256:439594978a49a09530cff7ebc4b5c7103ef57baf48d5ea3184f21d9a2befa098"}, ] [package.dependencies] markdown-it-py = ">=2.2.0" pygments = ">=2.13.0,<3.0.0" +typing-extensions = {version = ">=4.0.0,<5.0", markers = "python_version < \"3.11\""} [package.extras] jupyter = ["ipywidgets (>=7.5.1,<9)"] -[[package]] -name = "ruamel-yaml" -version = "0.18.6" -description = "ruamel.yaml is a YAML parser/emitter that supports roundtrip preservation of comments, seq/map flow style, and map key order" -optional = false -python-versions = ">=3.7" -files = [ - {file = "ruamel.yaml-0.18.6-py3-none-any.whl", hash = "sha256:57b53ba33def16c4f3d807c0ccbc00f8a6081827e81ba2491691b76882d0c636"}, - {file = "ruamel.yaml-0.18.6.tar.gz", hash = "sha256:8b27e6a217e786c6fbe5634d8f3f11bc63e0f80f6a5890f28863d9c45aac311b"}, -] - -[package.dependencies] -"ruamel.yaml.clib" = {version = ">=0.2.7", markers = "platform_python_implementation == \"CPython\" and python_version < \"3.13\""} - -[package.extras] -docs = ["mercurial (>5.7)", "ryd"] -jinja2 = ["ruamel.yaml.jinja2 (>=0.2)"] - -[[package]] -name = "ruamel-yaml-clib" -version = "0.2.8" -description = "C version of reader, parser and emitter for ruamel.yaml derived from libyaml" -optional = false -python-versions = ">=3.6" -files = [ - {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:b42169467c42b692c19cf539c38d4602069d8c1505e97b86387fcf7afb766e1d"}, - {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-macosx_13_0_arm64.whl", hash = "sha256:07238db9cbdf8fc1e9de2489a4f68474e70dffcb32232db7c08fa61ca0c7c462"}, - {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:fff3573c2db359f091e1589c3d7c5fc2f86f5bdb6f24252c2d8e539d4e45f412"}, - {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-manylinux_2_24_aarch64.whl", hash = "sha256:aa2267c6a303eb483de8d02db2871afb5c5fc15618d894300b88958f729ad74f"}, - {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:840f0c7f194986a63d2c2465ca63af8ccbbc90ab1c6001b1978f05119b5e7334"}, - {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:024cfe1fc7c7f4e1aff4a81e718109e13409767e4f871443cbff3dba3578203d"}, - {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-win32.whl", hash = "sha256:c69212f63169ec1cfc9bb44723bf2917cbbd8f6191a00ef3410f5a7fe300722d"}, - {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-win_amd64.whl", hash = "sha256:cabddb8d8ead485e255fe80429f833172b4cadf99274db39abc080e068cbcc31"}, - {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:bef08cd86169d9eafb3ccb0a39edb11d8e25f3dae2b28f5c52fd997521133069"}, - {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-macosx_13_0_arm64.whl", hash = "sha256:b16420e621d26fdfa949a8b4b47ade8810c56002f5389970db4ddda51dbff248"}, - {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:25c515e350e5b739842fc3228d662413ef28f295791af5e5110b543cf0b57d9b"}, - {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-manylinux_2_24_aarch64.whl", hash = "sha256:1707814f0d9791df063f8c19bb51b0d1278b8e9a2353abbb676c2f685dee6afe"}, - {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:46d378daaac94f454b3a0e3d8d78cafd78a026b1d71443f4966c696b48a6d899"}, - {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:09b055c05697b38ecacb7ac50bdab2240bfca1a0c4872b0fd309bb07dc9aa3a9"}, - {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-win32.whl", hash = "sha256:53a300ed9cea38cf5a2a9b069058137c2ca1ce658a874b79baceb8f892f915a7"}, - {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-win_amd64.whl", hash = "sha256:c2a72e9109ea74e511e29032f3b670835f8a59bbdc9ce692c5b4ed91ccf1eedb"}, - {file = "ruamel.yaml.clib-0.2.8-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:ebc06178e8821efc9692ea7544aa5644217358490145629914d8020042c24aa1"}, - {file = "ruamel.yaml.clib-0.2.8-cp312-cp312-macosx_13_0_arm64.whl", hash = "sha256:edaef1c1200c4b4cb914583150dcaa3bc30e592e907c01117c08b13a07255ec2"}, - {file = "ruamel.yaml.clib-0.2.8-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d176b57452ab5b7028ac47e7b3cf644bcfdc8cacfecf7e71759f7f51a59e5c92"}, - {file = "ruamel.yaml.clib-0.2.8-cp312-cp312-manylinux_2_24_aarch64.whl", hash = "sha256:1dc67314e7e1086c9fdf2680b7b6c2be1c0d8e3a8279f2e993ca2a7545fecf62"}, - {file = "ruamel.yaml.clib-0.2.8-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:3213ece08ea033eb159ac52ae052a4899b56ecc124bb80020d9bbceeb50258e9"}, - {file = "ruamel.yaml.clib-0.2.8-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:aab7fd643f71d7946f2ee58cc88c9b7bfc97debd71dcc93e03e2d174628e7e2d"}, - {file = "ruamel.yaml.clib-0.2.8-cp312-cp312-win32.whl", hash = "sha256:5c365d91c88390c8d0a8545df0b5857172824b1c604e867161e6b3d59a827eaa"}, - {file = "ruamel.yaml.clib-0.2.8-cp312-cp312-win_amd64.whl", hash = "sha256:1758ce7d8e1a29d23de54a16ae867abd370f01b5a69e1a3ba75223eaa3ca1a1b"}, - {file = "ruamel.yaml.clib-0.2.8-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:a5aa27bad2bb83670b71683aae140a1f52b0857a2deff56ad3f6c13a017a26ed"}, - {file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:c58ecd827313af6864893e7af0a3bb85fd529f862b6adbefe14643947cfe2942"}, - {file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-macosx_12_0_arm64.whl", hash = "sha256:f481f16baec5290e45aebdc2a5168ebc6d35189ae6fea7a58787613a25f6e875"}, - {file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-manylinux_2_24_aarch64.whl", hash = "sha256:77159f5d5b5c14f7c34073862a6b7d34944075d9f93e681638f6d753606c6ce6"}, - {file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:7f67a1ee819dc4562d444bbafb135832b0b909f81cc90f7aa00260968c9ca1b3"}, - {file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:4ecbf9c3e19f9562c7fdd462e8d18dd902a47ca046a2e64dba80699f0b6c09b7"}, - {file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:87ea5ff66d8064301a154b3933ae406b0863402a799b16e4a1d24d9fbbcbe0d3"}, - {file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-win32.whl", hash = "sha256:75e1ed13e1f9de23c5607fe6bd1aeaae21e523b32d83bb33918245361e9cc51b"}, - {file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-win_amd64.whl", hash = "sha256:3f215c5daf6a9d7bbed4a0a4f760f3113b10e82ff4c5c44bec20a68c8014f675"}, - {file = "ruamel.yaml.clib-0.2.8-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1b617618914cb00bf5c34d4357c37aa15183fa229b24767259657746c9077615"}, - {file = "ruamel.yaml.clib-0.2.8-cp38-cp38-macosx_12_0_arm64.whl", hash = "sha256:a6a9ffd280b71ad062eae53ac1659ad86a17f59a0fdc7699fd9be40525153337"}, - {file = "ruamel.yaml.clib-0.2.8-cp38-cp38-manylinux_2_24_aarch64.whl", hash = "sha256:305889baa4043a09e5b76f8e2a51d4ffba44259f6b4c72dec8ca56207d9c6fe1"}, - {file = "ruamel.yaml.clib-0.2.8-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:700e4ebb569e59e16a976857c8798aee258dceac7c7d6b50cab63e080058df91"}, - {file = "ruamel.yaml.clib-0.2.8-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:e2b4c44b60eadec492926a7270abb100ef9f72798e18743939bdbf037aab8c28"}, - {file = "ruamel.yaml.clib-0.2.8-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:e79e5db08739731b0ce4850bed599235d601701d5694c36570a99a0c5ca41a9d"}, - {file = "ruamel.yaml.clib-0.2.8-cp38-cp38-win32.whl", hash = "sha256:955eae71ac26c1ab35924203fda6220f84dce57d6d7884f189743e2abe3a9fbe"}, - {file = "ruamel.yaml.clib-0.2.8-cp38-cp38-win_amd64.whl", hash = "sha256:56f4252222c067b4ce51ae12cbac231bce32aee1d33fbfc9d17e5b8d6966c312"}, - {file = "ruamel.yaml.clib-0.2.8-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:03d1162b6d1df1caa3a4bd27aa51ce17c9afc2046c31b0ad60a0a96ec22f8001"}, - {file = "ruamel.yaml.clib-0.2.8-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:bba64af9fa9cebe325a62fa398760f5c7206b215201b0ec825005f1b18b9bccf"}, - {file = "ruamel.yaml.clib-0.2.8-cp39-cp39-manylinux_2_24_aarch64.whl", hash = "sha256:a1a45e0bb052edf6a1d3a93baef85319733a888363938e1fc9924cb00c8df24c"}, - {file = "ruamel.yaml.clib-0.2.8-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:da09ad1c359a728e112d60116f626cc9f29730ff3e0e7db72b9a2dbc2e4beed5"}, - {file = "ruamel.yaml.clib-0.2.8-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:184565012b60405d93838167f425713180b949e9d8dd0bbc7b49f074407c5a8b"}, - {file = "ruamel.yaml.clib-0.2.8-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a75879bacf2c987c003368cf14bed0ffe99e8e85acfa6c0bfffc21a090f16880"}, - {file = "ruamel.yaml.clib-0.2.8-cp39-cp39-win32.whl", hash = "sha256:84b554931e932c46f94ab306913ad7e11bba988104c5cff26d90d03f68258cd5"}, - {file = "ruamel.yaml.clib-0.2.8-cp39-cp39-win_amd64.whl", hash = "sha256:25ac8c08322002b06fa1d49d1646181f0b2c72f5cbc15a85e80b4c30a544bb15"}, - {file = "ruamel.yaml.clib-0.2.8.tar.gz", hash = "sha256:beb2e0404003de9a4cab9753a8805a8fe9320ee6673136ed7f04255fe60bb512"}, -] - [[package]] name = "ruff" version = "0.0.290" @@ -3570,13 +3219,13 @@ files = [ [[package]] name = "service-identity" -version = "24.1.0" +version = "24.2.0" description = "Service identity verification for pyOpenSSL & cryptography." optional = false python-versions = ">=3.8" files = [ - {file = "service_identity-24.1.0-py3-none-any.whl", hash = "sha256:a28caf8130c8a5c1c7a6f5293faaf239bbfb7751e4862436920ee6f2616f568a"}, - {file = "service_identity-24.1.0.tar.gz", hash = "sha256:6829c9d62fb832c2e1c435629b0a8c476e1929881f28bee4d20bc24161009221"}, + {file = "service_identity-24.2.0-py3-none-any.whl", hash = "sha256:6b047fbd8a84fd0bb0d55ebce4031e400562b9196e1e0d3e0fe2b8a59f6d4a85"}, + {file = "service_identity-24.2.0.tar.gz", hash = "sha256:b8683ba13f0d39c6cd5d625d2c5f65421d6d707b013b375c355751557cbe8e09"}, ] [package.dependencies] @@ -3586,7 +3235,7 @@ pyasn1 = "*" pyasn1-modules = "*" [package.extras] -dev = ["pyopenssl", "service-identity[idna,mypy,tests]"] +dev = ["coverage[toml] (>=5.0.2)", "idna", "mypy", "pyopenssl", "pytest", "types-pyopenssl"] docs = ["furo", "myst-parser", "pyopenssl", "sphinx", "sphinx-notfound-page"] idna = ["idna"] mypy = ["idna", "mypy", "types-pyopenssl"] @@ -3739,17 +3388,6 @@ files = [ {file = "sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc"}, ] -[[package]] -name = "sortedcontainers" -version = "2.4.0" -description = "Sorted Containers -- Sorted List, Sorted Dict, Sorted Set" -optional = false -python-versions = "*" -files = [ - {file = "sortedcontainers-2.4.0-py2.py3-none-any.whl", hash = "sha256:a163dcaede0f1c021485e957a39245190e74249897e2ae4b2aa38595db237ee0"}, - {file = "sortedcontainers-2.4.0.tar.gz", hash = "sha256:25caa5a06cc30b6b83d11423433f65d1f9d76c4c6a0c90e3379eaa43b9bfdb88"}, -] - [[package]] name = "soupsieve" version = "2.6" @@ -3883,20 +3521,6 @@ files = [ dev = ["build", "hatch"] doc = ["sphinx"] -[[package]] -name = "tabulate" -version = "0.9.0" -description = "Pretty-print tabular data" -optional = false -python-versions = ">=3.7" -files = [ - {file = "tabulate-0.9.0-py3-none-any.whl", hash = "sha256:024ca478df22e9340661486f85298cff5f6dcdba14f3813e8830015b9ed1948f"}, - {file = "tabulate-0.9.0.tar.gz", hash = "sha256:0095b12bf5966de529c0feb1fa08671671b3368eec77d7ef7ab114be2c068b3c"}, -] - -[package.extras] -widechars = ["wcwidth"] - [[package]] name = "tenacity" version = "8.1.0" @@ -3911,29 +3535,15 @@ files = [ [package.extras] doc = ["reno", "sphinx", "tornado (>=4.5)"] -[[package]] -name = "termcolor" -version = "2.4.0" -description = "ANSI color formatting for output in terminal" -optional = false -python-versions = ">=3.8" -files = [ - {file = "termcolor-2.4.0-py3-none-any.whl", hash = "sha256:9297c0df9c99445c2412e832e882a7884038a25617c60cea2ad69488d4040d63"}, - {file = "termcolor-2.4.0.tar.gz", hash = "sha256:aab9e56047c8ac41ed798fa36d892a37aca6b3e9159f3e0c24bc64a9b3ac7b7a"}, -] - -[package.extras] -tests = ["pytest", "pytest-cov"] - [[package]] name = "tldextract" -version = "3.5.0" +version = "5.1.2" description = "Accurately separates a URL's subdomain, domain, and public suffix, using the Public Suffix List (PSL). By default, this includes the public ICANN TLDs and their exceptions. You can optionally support the Public Suffix List's private domains as well." optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "tldextract-3.5.0-py3-none-any.whl", hash = "sha256:2cb271ca8d06ea1630a1361b58edad14e0cf81f34ce3c90b052854528fe2a281"}, - {file = "tldextract-3.5.0.tar.gz", hash = "sha256:4df1c65b95be61d59428e8611e955e54e6f1d4483d3e8d5733d3a9062155e910"}, + {file = "tldextract-5.1.2-py3-none-any.whl", hash = "sha256:4dfc4c277b6b97fa053899fcdb892d2dc27295851ab5fac4e07797b6a21b2e46"}, + {file = "tldextract-5.1.2.tar.gz", hash = "sha256:c9e17f756f05afb5abac04fe8f766e7e70f9fe387adb1859f0f52408ee060200"}, ] [package.dependencies] @@ -3942,51 +3552,35 @@ idna = "*" requests = ">=2.1.0" requests-file = ">=1.4" +[package.extras] +release = ["build", "twine"] +testing = ["black", "mypy", "pytest", "pytest-gitignore", "pytest-mock", "responses", "ruff", "syrupy", "tox", "types-filelock", "types-requests"] + [[package]] name = "tomli" -version = "2.0.1" +version = "2.0.2" description = "A lil' TOML parser" optional = false -python-versions = ">=3.7" -files = [ - {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"}, - {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, -] - -[[package]] -name = "tqdm" -version = "4.66.5" -description = "Fast, Extensible Progress Meter" -optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "tqdm-4.66.5-py3-none-any.whl", hash = "sha256:90279a3770753eafc9194a0364852159802111925aa30eb3f9d85b0e805ac7cd"}, - {file = "tqdm-4.66.5.tar.gz", hash = "sha256:e1020aef2e5096702d8a025ac7d16b1577279c9d63f8375b63083e9a5f0fcbad"}, + {file = "tomli-2.0.2-py3-none-any.whl", hash = "sha256:2ebe24485c53d303f690b0ec092806a085f07af5a5aa1464f3931eec36caaa38"}, + {file = "tomli-2.0.2.tar.gz", hash = "sha256:d46d457a85337051c36524bc5349dd91b1877838e2979ac5ced3e710ed8a60ed"}, ] -[package.dependencies] -colorama = {version = "*", markers = "platform_system == \"Windows\""} - -[package.extras] -dev = ["pytest (>=6)", "pytest-cov", "pytest-timeout", "pytest-xdist"] -notebook = ["ipywidgets (>=6)"] -slack = ["slack-sdk"] -telegram = ["requests"] - [[package]] name = "twisted" -version = "24.7.0" +version = "24.10.0" description = "An asynchronous networking framework written in Python" optional = false python-versions = ">=3.8.0" files = [ - {file = "twisted-24.7.0-py3-none-any.whl", hash = "sha256:734832ef98108136e222b5230075b1079dad8a3fc5637319615619a7725b0c81"}, - {file = "twisted-24.7.0.tar.gz", hash = "sha256:5a60147f044187a127ec7da96d170d49bcce50c6fd36f594e60f4587eff4d394"}, + {file = "twisted-24.10.0-py3-none-any.whl", hash = "sha256:67aa7c8aa94387385302acf44ade12967c747858c8bcce0f11d38077a11c5326"}, + {file = "twisted-24.10.0.tar.gz", hash = "sha256:02951299672595fea0f70fa2d5f7b5e3d56836157eda68859a6ad6492d36756e"}, ] [package.dependencies] -attrs = ">=21.3.0" -automat = ">=0.8.0" +attrs = ">=22.2.0" +automat = ">=24.8.0" constantly = ">=15.1" hyperlink = ">=17.1.1" idna = {version = ">=2.4", optional = true, markers = "extra == \"tls\""} @@ -3997,19 +3591,19 @@ typing-extensions = ">=4.2.0" zope-interface = ">=5" [package.extras] -all-non-platform = ["appdirs (>=1.4.0)", "appdirs (>=1.4.0)", "bcrypt (>=3.1.3)", "bcrypt (>=3.1.3)", "cryptography (>=3.3)", "cryptography (>=3.3)", "cython-test-exception-raiser (>=1.0.2,<2)", "cython-test-exception-raiser (>=1.0.2,<2)", "h2 (>=3.0,<5.0)", "h2 (>=3.0,<5.0)", "hypothesis (>=6.56)", "hypothesis (>=6.56)", "idna (>=2.4)", "idna (>=2.4)", "priority (>=1.1.0,<2.0)", "priority (>=1.1.0,<2.0)", "pyhamcrest (>=2)", "pyhamcrest (>=2)", "pyopenssl (>=21.0.0)", "pyopenssl (>=21.0.0)", "pyserial (>=3.0)", "pyserial (>=3.0)", "pywin32 (!=226)", "pywin32 (!=226)", "service-identity (>=18.1.0)", "service-identity (>=18.1.0)"] +all-non-platform = ["appdirs (>=1.4.0)", "appdirs (>=1.4.0)", "bcrypt (>=3.1.3)", "bcrypt (>=3.1.3)", "cryptography (>=3.3)", "cryptography (>=3.3)", "cython-test-exception-raiser (>=1.0.2,<2)", "cython-test-exception-raiser (>=1.0.2,<2)", "h2 (>=3.2,<5.0)", "h2 (>=3.2,<5.0)", "httpx[http2] (>=0.27)", "httpx[http2] (>=0.27)", "hypothesis (>=6.56)", "hypothesis (>=6.56)", "idna (>=2.4)", "idna (>=2.4)", "priority (>=1.1.0,<2.0)", "priority (>=1.1.0,<2.0)", "pyhamcrest (>=2)", "pyhamcrest (>=2)", "pyopenssl (>=21.0.0)", "pyopenssl (>=21.0.0)", "pyserial (>=3.0)", "pyserial (>=3.0)", "pywin32 (!=226)", "pywin32 (!=226)", "service-identity (>=18.1.0)", "service-identity (>=18.1.0)"] conch = ["appdirs (>=1.4.0)", "bcrypt (>=3.1.3)", "cryptography (>=3.3)"] -dev = ["coverage (>=7.5,<8.0)", "cython-test-exception-raiser (>=1.0.2,<2)", "hypothesis (>=6.56)", "pydoctor (>=23.9.0,<23.10.0)", "pyflakes (>=2.2,<3.0)", "pyhamcrest (>=2)", "python-subunit (>=1.4,<2.0)", "sphinx (>=6,<7)", "sphinx-rtd-theme (>=1.3,<2.0)", "towncrier (>=23.6,<24.0)", "twistedchecker (>=0.7,<1.0)"] +dev = ["coverage (>=7.5,<8.0)", "cython-test-exception-raiser (>=1.0.2,<2)", "httpx[http2] (>=0.27)", "hypothesis (>=6.56)", "pydoctor (>=23.9.0,<23.10.0)", "pyflakes (>=2.2,<3.0)", "pyhamcrest (>=2)", "python-subunit (>=1.4,<2.0)", "sphinx (>=6,<7)", "sphinx-rtd-theme (>=1.3,<2.0)", "towncrier (>=23.6,<24.0)", "twistedchecker (>=0.7,<1.0)"] dev-release = ["pydoctor (>=23.9.0,<23.10.0)", "pydoctor (>=23.9.0,<23.10.0)", "sphinx (>=6,<7)", "sphinx (>=6,<7)", "sphinx-rtd-theme (>=1.3,<2.0)", "sphinx-rtd-theme (>=1.3,<2.0)", "towncrier (>=23.6,<24.0)", "towncrier (>=23.6,<24.0)"] -gtk-platform = ["appdirs (>=1.4.0)", "appdirs (>=1.4.0)", "bcrypt (>=3.1.3)", "bcrypt (>=3.1.3)", "cryptography (>=3.3)", "cryptography (>=3.3)", "cython-test-exception-raiser (>=1.0.2,<2)", "cython-test-exception-raiser (>=1.0.2,<2)", "h2 (>=3.0,<5.0)", "h2 (>=3.0,<5.0)", "hypothesis (>=6.56)", "hypothesis (>=6.56)", "idna (>=2.4)", "idna (>=2.4)", "priority (>=1.1.0,<2.0)", "priority (>=1.1.0,<2.0)", "pygobject", "pygobject", "pyhamcrest (>=2)", "pyhamcrest (>=2)", "pyopenssl (>=21.0.0)", "pyopenssl (>=21.0.0)", "pyserial (>=3.0)", "pyserial (>=3.0)", "pywin32 (!=226)", "pywin32 (!=226)", "service-identity (>=18.1.0)", "service-identity (>=18.1.0)"] -http2 = ["h2 (>=3.0,<5.0)", "priority (>=1.1.0,<2.0)"] -macos-platform = ["appdirs (>=1.4.0)", "appdirs (>=1.4.0)", "bcrypt (>=3.1.3)", "bcrypt (>=3.1.3)", "cryptography (>=3.3)", "cryptography (>=3.3)", "cython-test-exception-raiser (>=1.0.2,<2)", "cython-test-exception-raiser (>=1.0.2,<2)", "h2 (>=3.0,<5.0)", "h2 (>=3.0,<5.0)", "hypothesis (>=6.56)", "hypothesis (>=6.56)", "idna (>=2.4)", "idna (>=2.4)", "priority (>=1.1.0,<2.0)", "priority (>=1.1.0,<2.0)", "pyhamcrest (>=2)", "pyhamcrest (>=2)", "pyobjc-core", "pyobjc-core", "pyobjc-framework-cfnetwork", "pyobjc-framework-cfnetwork", "pyobjc-framework-cocoa", "pyobjc-framework-cocoa", "pyopenssl (>=21.0.0)", "pyopenssl (>=21.0.0)", "pyserial (>=3.0)", "pyserial (>=3.0)", "pywin32 (!=226)", "pywin32 (!=226)", "service-identity (>=18.1.0)", "service-identity (>=18.1.0)"] -mypy = ["appdirs (>=1.4.0)", "bcrypt (>=3.1.3)", "coverage (>=7.5,<8.0)", "cryptography (>=3.3)", "cython-test-exception-raiser (>=1.0.2,<2)", "h2 (>=3.0,<5.0)", "hypothesis (>=6.56)", "idna (>=2.4)", "mypy (>=1.8,<2.0)", "mypy-zope (>=1.0.3,<1.1.0)", "priority (>=1.1.0,<2.0)", "pydoctor (>=23.9.0,<23.10.0)", "pyflakes (>=2.2,<3.0)", "pyhamcrest (>=2)", "pyopenssl (>=21.0.0)", "pyserial (>=3.0)", "python-subunit (>=1.4,<2.0)", "pywin32 (!=226)", "service-identity (>=18.1.0)", "sphinx (>=6,<7)", "sphinx-rtd-theme (>=1.3,<2.0)", "towncrier (>=23.6,<24.0)", "twistedchecker (>=0.7,<1.0)", "types-pyopenssl", "types-setuptools"] -osx-platform = ["appdirs (>=1.4.0)", "appdirs (>=1.4.0)", "bcrypt (>=3.1.3)", "bcrypt (>=3.1.3)", "cryptography (>=3.3)", "cryptography (>=3.3)", "cython-test-exception-raiser (>=1.0.2,<2)", "cython-test-exception-raiser (>=1.0.2,<2)", "h2 (>=3.0,<5.0)", "h2 (>=3.0,<5.0)", "hypothesis (>=6.56)", "hypothesis (>=6.56)", "idna (>=2.4)", "idna (>=2.4)", "priority (>=1.1.0,<2.0)", "priority (>=1.1.0,<2.0)", "pyhamcrest (>=2)", "pyhamcrest (>=2)", "pyobjc-core", "pyobjc-core", "pyobjc-framework-cfnetwork", "pyobjc-framework-cfnetwork", "pyobjc-framework-cocoa", "pyobjc-framework-cocoa", "pyopenssl (>=21.0.0)", "pyopenssl (>=21.0.0)", "pyserial (>=3.0)", "pyserial (>=3.0)", "pywin32 (!=226)", "pywin32 (!=226)", "service-identity (>=18.1.0)", "service-identity (>=18.1.0)"] +gtk-platform = ["appdirs (>=1.4.0)", "appdirs (>=1.4.0)", "bcrypt (>=3.1.3)", "bcrypt (>=3.1.3)", "cryptography (>=3.3)", "cryptography (>=3.3)", "cython-test-exception-raiser (>=1.0.2,<2)", "cython-test-exception-raiser (>=1.0.2,<2)", "h2 (>=3.2,<5.0)", "h2 (>=3.2,<5.0)", "httpx[http2] (>=0.27)", "httpx[http2] (>=0.27)", "hypothesis (>=6.56)", "hypothesis (>=6.56)", "idna (>=2.4)", "idna (>=2.4)", "priority (>=1.1.0,<2.0)", "priority (>=1.1.0,<2.0)", "pygobject", "pygobject", "pyhamcrest (>=2)", "pyhamcrest (>=2)", "pyopenssl (>=21.0.0)", "pyopenssl (>=21.0.0)", "pyserial (>=3.0)", "pyserial (>=3.0)", "pywin32 (!=226)", "pywin32 (!=226)", "service-identity (>=18.1.0)", "service-identity (>=18.1.0)"] +http2 = ["h2 (>=3.2,<5.0)", "priority (>=1.1.0,<2.0)"] +macos-platform = ["appdirs (>=1.4.0)", "appdirs (>=1.4.0)", "bcrypt (>=3.1.3)", "bcrypt (>=3.1.3)", "cryptography (>=3.3)", "cryptography (>=3.3)", "cython-test-exception-raiser (>=1.0.2,<2)", "cython-test-exception-raiser (>=1.0.2,<2)", "h2 (>=3.2,<5.0)", "h2 (>=3.2,<5.0)", "httpx[http2] (>=0.27)", "httpx[http2] (>=0.27)", "hypothesis (>=6.56)", "hypothesis (>=6.56)", "idna (>=2.4)", "idna (>=2.4)", "priority (>=1.1.0,<2.0)", "priority (>=1.1.0,<2.0)", "pyhamcrest (>=2)", "pyhamcrest (>=2)", "pyobjc-core", "pyobjc-core", "pyobjc-framework-cfnetwork", "pyobjc-framework-cfnetwork", "pyobjc-framework-cocoa", "pyobjc-framework-cocoa", "pyopenssl (>=21.0.0)", "pyopenssl (>=21.0.0)", "pyserial (>=3.0)", "pyserial (>=3.0)", "pywin32 (!=226)", "pywin32 (!=226)", "service-identity (>=18.1.0)", "service-identity (>=18.1.0)"] +mypy = ["appdirs (>=1.4.0)", "bcrypt (>=3.1.3)", "coverage (>=7.5,<8.0)", "cryptography (>=3.3)", "cython-test-exception-raiser (>=1.0.2,<2)", "h2 (>=3.2,<5.0)", "httpx[http2] (>=0.27)", "hypothesis (>=6.56)", "idna (>=2.4)", "mypy (==1.10.1)", "mypy-zope (==1.0.6)", "priority (>=1.1.0,<2.0)", "pydoctor (>=23.9.0,<23.10.0)", "pyflakes (>=2.2,<3.0)", "pyhamcrest (>=2)", "pyopenssl (>=21.0.0)", "pyserial (>=3.0)", "python-subunit (>=1.4,<2.0)", "pywin32 (!=226)", "service-identity (>=18.1.0)", "sphinx (>=6,<7)", "sphinx-rtd-theme (>=1.3,<2.0)", "towncrier (>=23.6,<24.0)", "twistedchecker (>=0.7,<1.0)", "types-pyopenssl", "types-setuptools"] +osx-platform = ["appdirs (>=1.4.0)", "appdirs (>=1.4.0)", "bcrypt (>=3.1.3)", "bcrypt (>=3.1.3)", "cryptography (>=3.3)", "cryptography (>=3.3)", "cython-test-exception-raiser (>=1.0.2,<2)", "cython-test-exception-raiser (>=1.0.2,<2)", "h2 (>=3.2,<5.0)", "h2 (>=3.2,<5.0)", "httpx[http2] (>=0.27)", "httpx[http2] (>=0.27)", "hypothesis (>=6.56)", "hypothesis (>=6.56)", "idna (>=2.4)", "idna (>=2.4)", "priority (>=1.1.0,<2.0)", "priority (>=1.1.0,<2.0)", "pyhamcrest (>=2)", "pyhamcrest (>=2)", "pyobjc-core", "pyobjc-core", "pyobjc-framework-cfnetwork", "pyobjc-framework-cfnetwork", "pyobjc-framework-cocoa", "pyobjc-framework-cocoa", "pyopenssl (>=21.0.0)", "pyopenssl (>=21.0.0)", "pyserial (>=3.0)", "pyserial (>=3.0)", "pywin32 (!=226)", "pywin32 (!=226)", "service-identity (>=18.1.0)", "service-identity (>=18.1.0)"] serial = ["pyserial (>=3.0)", "pywin32 (!=226)"] -test = ["cython-test-exception-raiser (>=1.0.2,<2)", "hypothesis (>=6.56)", "pyhamcrest (>=2)"] +test = ["cython-test-exception-raiser (>=1.0.2,<2)", "httpx[http2] (>=0.27)", "hypothesis (>=6.56)", "pyhamcrest (>=2)"] tls = ["idna (>=2.4)", "pyopenssl (>=21.0.0)", "service-identity (>=18.1.0)"] -windows-platform = ["appdirs (>=1.4.0)", "appdirs (>=1.4.0)", "bcrypt (>=3.1.3)", "bcrypt (>=3.1.3)", "cryptography (>=3.3)", "cryptography (>=3.3)", "cython-test-exception-raiser (>=1.0.2,<2)", "cython-test-exception-raiser (>=1.0.2,<2)", "h2 (>=3.0,<5.0)", "h2 (>=3.0,<5.0)", "hypothesis (>=6.56)", "hypothesis (>=6.56)", "idna (>=2.4)", "idna (>=2.4)", "priority (>=1.1.0,<2.0)", "priority (>=1.1.0,<2.0)", "pyhamcrest (>=2)", "pyhamcrest (>=2)", "pyopenssl (>=21.0.0)", "pyopenssl (>=21.0.0)", "pyserial (>=3.0)", "pyserial (>=3.0)", "pywin32 (!=226)", "pywin32 (!=226)", "pywin32 (!=226)", "pywin32 (!=226)", "service-identity (>=18.1.0)", "service-identity (>=18.1.0)", "twisted-iocpsupport (>=1.0.2)", "twisted-iocpsupport (>=1.0.2)"] +windows-platform = ["appdirs (>=1.4.0)", "appdirs (>=1.4.0)", "bcrypt (>=3.1.3)", "bcrypt (>=3.1.3)", "cryptography (>=3.3)", "cryptography (>=3.3)", "cython-test-exception-raiser (>=1.0.2,<2)", "cython-test-exception-raiser (>=1.0.2,<2)", "h2 (>=3.2,<5.0)", "h2 (>=3.2,<5.0)", "httpx[http2] (>=0.27)", "httpx[http2] (>=0.27)", "hypothesis (>=6.56)", "hypothesis (>=6.56)", "idna (>=2.4)", "idna (>=2.4)", "priority (>=1.1.0,<2.0)", "priority (>=1.1.0,<2.0)", "pyhamcrest (>=2)", "pyhamcrest (>=2)", "pyopenssl (>=21.0.0)", "pyopenssl (>=21.0.0)", "pyserial (>=3.0)", "pyserial (>=3.0)", "pywin32 (!=226)", "pywin32 (!=226)", "pywin32 (!=226)", "pywin32 (!=226)", "service-identity (>=18.1.0)", "service-identity (>=18.1.0)", "twisted-iocpsupport (>=1.0.2)", "twisted-iocpsupport (>=1.0.2)"] [[package]] name = "txaio" @@ -4113,57 +3707,64 @@ standard = ["colorama (>=0.4)", "httptools (>=0.4.0)", "python-dotenv (>=0.13)", [[package]] name = "uvloop" -version = "0.20.0" +version = "0.21.0" description = "Fast implementation of asyncio event loop on top of libuv" optional = false python-versions = ">=3.8.0" files = [ - {file = "uvloop-0.20.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:9ebafa0b96c62881d5cafa02d9da2e44c23f9f0cd829f3a32a6aff771449c996"}, - {file = "uvloop-0.20.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:35968fc697b0527a06e134999eef859b4034b37aebca537daeb598b9d45a137b"}, - {file = "uvloop-0.20.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b16696f10e59d7580979b420eedf6650010a4a9c3bd8113f24a103dfdb770b10"}, - {file = "uvloop-0.20.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9b04d96188d365151d1af41fa2d23257b674e7ead68cfd61c725a422764062ae"}, - {file = "uvloop-0.20.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:94707205efbe809dfa3a0d09c08bef1352f5d3d6612a506f10a319933757c006"}, - {file = "uvloop-0.20.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:89e8d33bb88d7263f74dc57d69f0063e06b5a5ce50bb9a6b32f5fcbe655f9e73"}, - {file = "uvloop-0.20.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:e50289c101495e0d1bb0bfcb4a60adde56e32f4449a67216a1ab2750aa84f037"}, - {file = "uvloop-0.20.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:e237f9c1e8a00e7d9ddaa288e535dc337a39bcbf679f290aee9d26df9e72bce9"}, - {file = "uvloop-0.20.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:746242cd703dc2b37f9d8b9f173749c15e9a918ddb021575a0205ec29a38d31e"}, - {file = "uvloop-0.20.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:82edbfd3df39fb3d108fc079ebc461330f7c2e33dbd002d146bf7c445ba6e756"}, - {file = "uvloop-0.20.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:80dc1b139516be2077b3e57ce1cb65bfed09149e1d175e0478e7a987863b68f0"}, - {file = "uvloop-0.20.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:4f44af67bf39af25db4c1ac27e82e9665717f9c26af2369c404be865c8818dcf"}, - {file = "uvloop-0.20.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:4b75f2950ddb6feed85336412b9a0c310a2edbcf4cf931aa5cfe29034829676d"}, - {file = "uvloop-0.20.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:77fbc69c287596880ecec2d4c7a62346bef08b6209749bf6ce8c22bbaca0239e"}, - {file = "uvloop-0.20.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6462c95f48e2d8d4c993a2950cd3d31ab061864d1c226bbf0ee2f1a8f36674b9"}, - {file = "uvloop-0.20.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:649c33034979273fa71aa25d0fe120ad1777c551d8c4cd2c0c9851d88fcb13ab"}, - {file = "uvloop-0.20.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:3a609780e942d43a275a617c0839d85f95c334bad29c4c0918252085113285b5"}, - {file = "uvloop-0.20.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:aea15c78e0d9ad6555ed201344ae36db5c63d428818b4b2a42842b3870127c00"}, - {file = "uvloop-0.20.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:f0e94b221295b5e69de57a1bd4aeb0b3a29f61be6e1b478bb8a69a73377db7ba"}, - {file = "uvloop-0.20.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:fee6044b64c965c425b65a4e17719953b96e065c5b7e09b599ff332bb2744bdf"}, - {file = "uvloop-0.20.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:265a99a2ff41a0fd56c19c3838b29bf54d1d177964c300dad388b27e84fd7847"}, - {file = "uvloop-0.20.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b10c2956efcecb981bf9cfb8184d27d5d64b9033f917115a960b83f11bfa0d6b"}, - {file = "uvloop-0.20.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:e7d61fe8e8d9335fac1bf8d5d82820b4808dd7a43020c149b63a1ada953d48a6"}, - {file = "uvloop-0.20.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:2beee18efd33fa6fdb0976e18475a4042cd31c7433c866e8a09ab604c7c22ff2"}, - {file = "uvloop-0.20.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:d8c36fdf3e02cec92aed2d44f63565ad1522a499c654f07935c8f9d04db69e95"}, - {file = "uvloop-0.20.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:a0fac7be202596c7126146660725157d4813aa29a4cc990fe51346f75ff8fde7"}, - {file = "uvloop-0.20.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9d0fba61846f294bce41eb44d60d58136090ea2b5b99efd21cbdf4e21927c56a"}, - {file = "uvloop-0.20.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:95720bae002ac357202e0d866128eb1ac82545bcf0b549b9abe91b5178d9b541"}, - {file = "uvloop-0.20.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:36c530d8fa03bfa7085af54a48f2ca16ab74df3ec7108a46ba82fd8b411a2315"}, - {file = "uvloop-0.20.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:e97152983442b499d7a71e44f29baa75b3b02e65d9c44ba53b10338e98dedb66"}, - {file = "uvloop-0.20.0.tar.gz", hash = "sha256:4603ca714a754fc8d9b197e325db25b2ea045385e8a3ad05d3463de725fdf469"}, + {file = "uvloop-0.21.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:ec7e6b09a6fdded42403182ab6b832b71f4edaf7f37a9a0e371a01db5f0cb45f"}, + {file = "uvloop-0.21.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:196274f2adb9689a289ad7d65700d37df0c0930fd8e4e743fa4834e850d7719d"}, + {file = "uvloop-0.21.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f38b2e090258d051d68a5b14d1da7203a3c3677321cf32a95a6f4db4dd8b6f26"}, + {file = "uvloop-0.21.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:87c43e0f13022b998eb9b973b5e97200c8b90823454d4bc06ab33829e09fb9bb"}, + {file = "uvloop-0.21.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:10d66943def5fcb6e7b37310eb6b5639fd2ccbc38df1177262b0640c3ca68c1f"}, + {file = "uvloop-0.21.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:67dd654b8ca23aed0a8e99010b4c34aca62f4b7fce88f39d452ed7622c94845c"}, + {file = "uvloop-0.21.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:c0f3fa6200b3108919f8bdabb9a7f87f20e7097ea3c543754cabc7d717d95cf8"}, + {file = "uvloop-0.21.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:0878c2640cf341b269b7e128b1a5fed890adc4455513ca710d77d5e93aa6d6a0"}, + {file = "uvloop-0.21.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b9fb766bb57b7388745d8bcc53a359b116b8a04c83a2288069809d2b3466c37e"}, + {file = "uvloop-0.21.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8a375441696e2eda1c43c44ccb66e04d61ceeffcd76e4929e527b7fa401b90fb"}, + {file = "uvloop-0.21.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:baa0e6291d91649c6ba4ed4b2f982f9fa165b5bbd50a9e203c416a2797bab3c6"}, + {file = "uvloop-0.21.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:4509360fcc4c3bd2c70d87573ad472de40c13387f5fda8cb58350a1d7475e58d"}, + {file = "uvloop-0.21.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:359ec2c888397b9e592a889c4d72ba3d6befba8b2bb01743f72fffbde663b59c"}, + {file = "uvloop-0.21.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:f7089d2dc73179ce5ac255bdf37c236a9f914b264825fdaacaded6990a7fb4c2"}, + {file = "uvloop-0.21.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:baa4dcdbd9ae0a372f2167a207cd98c9f9a1ea1188a8a526431eef2f8116cc8d"}, + {file = "uvloop-0.21.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:86975dca1c773a2c9864f4c52c5a55631038e387b47eaf56210f873887b6c8dc"}, + {file = "uvloop-0.21.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:461d9ae6660fbbafedd07559c6a2e57cd553b34b0065b6550685f6653a98c1cb"}, + {file = "uvloop-0.21.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:183aef7c8730e54c9a3ee3227464daed66e37ba13040bb3f350bc2ddc040f22f"}, + {file = "uvloop-0.21.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:bfd55dfcc2a512316e65f16e503e9e450cab148ef11df4e4e679b5e8253a5281"}, + {file = "uvloop-0.21.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:787ae31ad8a2856fc4e7c095341cccc7209bd657d0e71ad0dc2ea83c4a6fa8af"}, + {file = "uvloop-0.21.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5ee4d4ef48036ff6e5cfffb09dd192c7a5027153948d85b8da7ff705065bacc6"}, + {file = "uvloop-0.21.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f3df876acd7ec037a3d005b3ab85a7e4110422e4d9c1571d4fc89b0fc41b6816"}, + {file = "uvloop-0.21.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:bd53ecc9a0f3d87ab847503c2e1552b690362e005ab54e8a48ba97da3924c0dc"}, + {file = "uvloop-0.21.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a5c39f217ab3c663dc699c04cbd50c13813e31d917642d459fdcec07555cc553"}, + {file = "uvloop-0.21.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:17df489689befc72c39a08359efac29bbee8eee5209650d4b9f34df73d22e414"}, + {file = "uvloop-0.21.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:bc09f0ff191e61c2d592a752423c767b4ebb2986daa9ed62908e2b1b9a9ae206"}, + {file = "uvloop-0.21.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f0ce1b49560b1d2d8a2977e3ba4afb2414fb46b86a1b64056bc4ab929efdafbe"}, + {file = "uvloop-0.21.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e678ad6fe52af2c58d2ae3c73dc85524ba8abe637f134bf3564ed07f555c5e79"}, + {file = "uvloop-0.21.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:460def4412e473896ef179a1671b40c039c7012184b627898eea5072ef6f017a"}, + {file = "uvloop-0.21.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:10da8046cc4a8f12c91a1c39d1dd1585c41162a15caaef165c2174db9ef18bdc"}, + {file = "uvloop-0.21.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:c097078b8031190c934ed0ebfee8cc5f9ba9642e6eb88322b9958b649750f72b"}, + {file = "uvloop-0.21.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:46923b0b5ee7fc0020bef24afe7836cb068f5050ca04caf6b487c513dc1a20b2"}, + {file = "uvloop-0.21.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:53e420a3afe22cdcf2a0f4846e377d16e718bc70103d7088a4f7623567ba5fb0"}, + {file = "uvloop-0.21.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:88cb67cdbc0e483da00af0b2c3cdad4b7c61ceb1ee0f33fe00e09c81e3a6cb75"}, + {file = "uvloop-0.21.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:221f4f2a1f46032b403bf3be628011caf75428ee3cc204a22addf96f586b19fd"}, + {file = "uvloop-0.21.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:2d1f581393673ce119355d56da84fe1dd9d2bb8b3d13ce792524e1607139feff"}, + {file = "uvloop-0.21.0.tar.gz", hash = "sha256:3bf12b0fda68447806a7ad847bfa591613177275d35b6724b1ee573faa3704e3"}, ] [package.extras] +dev = ["Cython (>=3.0,<4.0)", "setuptools (>=60)"] docs = ["Sphinx (>=4.1.2,<4.2.0)", "sphinx-rtd-theme (>=0.5.2,<0.6.0)", "sphinxcontrib-asyncio (>=0.3.0,<0.4.0)"] -test = ["Cython (>=0.29.36,<0.30.0)", "aiohttp (==3.9.0b0)", "aiohttp (>=3.8.1)", "flake8 (>=5.0,<6.0)", "mypy (>=0.800)", "psutil", "pyOpenSSL (>=23.0.0,<23.1.0)", "pycodestyle (>=2.9.0,<2.10.0)"] +test = ["aiohttp (>=3.10.5)", "flake8 (>=5.0,<6.0)", "mypy (>=0.800)", "psutil", "pyOpenSSL (>=23.0.0,<23.1.0)", "pycodestyle (>=2.9.0,<2.10.0)"] [[package]] name = "virtualenv" -version = "20.26.6" +version = "20.27.1" description = "Virtual Python Environment builder" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "virtualenv-20.26.6-py3-none-any.whl", hash = "sha256:7345cc5b25405607a624d8418154577459c3e0277f5466dd79c49d5e492995f2"}, - {file = "virtualenv-20.26.6.tar.gz", hash = "sha256:280aede09a2a5c317e409a00102e7077c6432c5a38f0ef938e643805a7ad2c48"}, + {file = "virtualenv-20.27.1-py3-none-any.whl", hash = "sha256:f11f1b8a29525562925f745563bfd48b189450f61fb34c4f9cc79dd5aa32a1f4"}, + {file = "virtualenv-20.27.1.tar.gz", hash = "sha256:142c6be10212543b32c6c45d3d3893dff89112cc588b7d0879ae5a1ec03a47ba"}, ] [package.dependencies] @@ -4175,52 +3776,6 @@ platformdirs = ">=3.9.1,<5" docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx (>=7.1.2,!=7.3)", "sphinx-argparse (>=0.4)", "sphinxcontrib-towncrier (>=0.2.1a0)", "towncrier (>=23.6)"] test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess (>=1)", "flaky (>=3.7)", "packaging (>=23.1)", "pytest (>=7.4)", "pytest-env (>=0.8.2)", "pytest-freezer (>=0.4.8)", "pytest-mock (>=3.11.1)", "pytest-randomly (>=3.12)", "pytest-timeout (>=2.1)", "setuptools (>=68)", "time-machine (>=2.10)"] -[[package]] -name = "viv-utils" -version = "0.7.11" -description = "Utilities for binary analysis using vivisect." -optional = false -python-versions = ">=3.8" -files = [ - {file = "viv_utils-0.7.11-py2.py3-none-any.whl", hash = "sha256:ab44c428315e014a52dbbaab6862876dd0cd2c930a138a1655c1c5be7270d81b"}, -] - -[package.dependencies] -funcy = ">=2.0" -intervaltree = ">=3.1.0" -pefile = ">=2023.2.7" -python-flirt = {version = "0.8.10", optional = true, markers = "extra == \"flirt\""} -typing-extensions = ">=4.5.0" -vivisect = ">=1.1.0" - -[package.extras] -build = ["build (==1.2.1)", "setuptools (==70.0.0)"] -dev = ["black (==24.4.2)", "isort (==5.11.5)", "mypy (==1.10.0)", "pycodestyle (==2.11.1)", "pytest (==8.2.2)", "pytest-instafail (==0.5.0)", "pytest-sugar (==0.9.6)", "types-setuptools (==70.0.0.20240524)"] -flirt = ["python-flirt (==0.8.10)"] - -[[package]] -name = "vivisect" -version = "1.2.1" -description = "Pure python disassembler, debugger, emulator, and static analysis framework" -optional = false -python-versions = ">=3.8" -files = [ - {file = "vivisect-1.2.1-py3-none-any.whl", hash = "sha256:62eb383013318efcd42f2565e4ab5323ebb1fb6b2e8e9e7e432bd126743eccda"}, - {file = "vivisect-1.2.1.tar.gz", hash = "sha256:cc15ab541b9be3cad8060ee4f420e680258fa4fcf7477f3f9ad5023353f73299"}, -] - -[package.dependencies] -cxxfilt = ">=0.3.0,<0.4.0" -msgpack = ">=1.0.0,<1.1.0" -pyasn1 = ">=0.5.0,<0.6.0" -pyasn1-modules = ">=0.3.0,<0.4.0" -pycparser = ">=2.20" - -[package.extras] -dev = ["bump2version (>=1.0.0,<1.1.0)"] -docs = ["sphinx (>=7.1.0,<7.2.0)", "sphinx-rtd-theme (>=1.2.0,<1.3.0)"] -gui = ["pyqt5 (==5.15.7)", "pyqtwebengine (==5.15.6)"] - [[package]] name = "watchfiles" version = "0.24.0" @@ -4316,17 +3871,6 @@ files = [ [package.dependencies] anyio = ">=3.0.0" -[[package]] -name = "wcwidth" -version = "0.2.13" -description = "Measures the displayed width of unicode strings in a terminal" -optional = false -python-versions = "*" -files = [ - {file = "wcwidth-0.2.13-py2.py3-none-any.whl", hash = "sha256:3da69048e4540d84af32131829ff948f1e022c1c6bdb8d6102117aac784f6859"}, - {file = "wcwidth-0.2.13.tar.gz", hash = "sha256:72ea0c06399eb286d978fdedb6923a9eb47e1c486ce63e9b4e64fc18303972b5"}, -] - [[package]] name = "websockets" version = "13.1" @@ -4463,17 +4007,6 @@ files = [ {file = "win_unicode_console-0.5.zip", hash = "sha256:d4142d4d56d46f449d6f00536a73625a871cba040f0bc1a2e305a04578f07d1e"}, ] -[[package]] -name = "xmltodict" -version = "0.13.0" -description = "Makes working with XML feel like you are working with JSON" -optional = false -python-versions = ">=3.4" -files = [ - {file = "xmltodict-0.13.0-py2.py3-none-any.whl", hash = "sha256:aa89e8fd76320154a40d19a0df04a4695fb9dc5ba977cbb68ab3e4eb225e7852"}, - {file = "xmltodict-0.13.0.tar.gz", hash = "sha256:341595a488e3e01a85a9d8911d8912fd922ede5fecc4dce437eb4b6c8d037e56"}, -] - [[package]] name = "yara-python" version = "4.5.1" @@ -4583,54 +4116,57 @@ test = ["zope.testrunner"] [[package]] name = "zope-interface" -version = "7.0.3" +version = "7.1.1" description = "Interfaces for Python" optional = false python-versions = ">=3.8" files = [ - {file = "zope.interface-7.0.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:9b9369671a20b8d039b8e5a1a33abd12e089e319a3383b4cc0bf5c67bd05fe7b"}, - {file = "zope.interface-7.0.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:db6237e8fa91ea4f34d7e2d16d74741187e9105a63bbb5686c61fea04cdbacca"}, - {file = "zope.interface-7.0.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:53d678bb1c3b784edbfb0adeebfeea6bf479f54da082854406a8f295d36f8386"}, - {file = "zope.interface-7.0.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3aa8fcbb0d3c2be1bfd013a0f0acd636f6ed570c287743ae2bbd467ee967154d"}, - {file = "zope.interface-7.0.3-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6195c3c03fef9f87c0dbee0b3b6451df6e056322463cf35bca9a088e564a3c58"}, - {file = "zope.interface-7.0.3-cp310-cp310-win_amd64.whl", hash = "sha256:11fa1382c3efb34abf16becff8cb214b0b2e3144057c90611621f2d186b7e1b7"}, - {file = "zope.interface-7.0.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:af94e429f9d57b36e71ef4e6865182090648aada0cb2d397ae2b3f7fc478493a"}, - {file = "zope.interface-7.0.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:6dd647fcd765030638577fe6984284e0ebba1a1008244c8a38824be096e37fe3"}, - {file = "zope.interface-7.0.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1bee1b722077d08721005e8da493ef3adf0b7908e0cd85cc7dc836ac117d6f32"}, - {file = "zope.interface-7.0.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2545d6d7aac425d528cd9bf0d9e55fcd47ab7fd15f41a64b1c4bf4c6b24946dc"}, - {file = "zope.interface-7.0.3-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6d04b11ea47c9c369d66340dbe51e9031df2a0de97d68f442305ed7625ad6493"}, - {file = "zope.interface-7.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:064ade95cb54c840647205987c7b557f75d2b2f7d1a84bfab4cf81822ef6e7d1"}, - {file = "zope.interface-7.0.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:3fcdc76d0cde1c09c37b7c6b0f8beba2d857d8417b055d4f47df9c34ec518bdd"}, - {file = "zope.interface-7.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:3d4b91821305c8d8f6e6207639abcbdaf186db682e521af7855d0bea3047c8ca"}, - {file = "zope.interface-7.0.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:35062d93bc49bd9b191331c897a96155ffdad10744ab812485b6bad5b588d7e4"}, - {file = "zope.interface-7.0.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c96b3e6b0d4f6ddfec4e947130ec30bd2c7b19db6aa633777e46c8eecf1d6afd"}, - {file = "zope.interface-7.0.3-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e0c151a6c204f3830237c59ee4770cc346868a7a1af6925e5e38650141a7f05"}, - {file = "zope.interface-7.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:3de1d553ce72868b77a7e9d598c9bff6d3816ad2b4cc81c04f9d8914603814f3"}, - {file = "zope.interface-7.0.3-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ab985c566a99cc5f73bc2741d93f1ed24a2cc9da3890144d37b9582965aff996"}, - {file = "zope.interface-7.0.3-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d976fa7b5faf5396eb18ce6c132c98e05504b52b60784e3401f4ef0b2e66709b"}, - {file = "zope.interface-7.0.3-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:21a207c6b2c58def5011768140861a73f5240f4f39800625072ba84e76c9da0b"}, - {file = "zope.interface-7.0.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:382d31d1e68877061daaa6499468e9eb38eb7625d4369b1615ac08d3860fe896"}, - {file = "zope.interface-7.0.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:2c4316a30e216f51acbd9fb318aa5af2e362b716596d82cbb92f9101c8f8d2e7"}, - {file = "zope.interface-7.0.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:01e6e58078ad2799130c14a1d34ec89044ada0e1495329d72ee0407b9ae5100d"}, - {file = "zope.interface-7.0.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:799ef7a444aebbad5a145c3b34bff012b54453cddbde3332d47ca07225792ea4"}, - {file = "zope.interface-7.0.3-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d3b7ce6d46fb0e60897d62d1ff370790ce50a57d40a651db91a3dde74f73b738"}, - {file = "zope.interface-7.0.3-cp38-cp38-win_amd64.whl", hash = "sha256:f418c88f09c3ba159b95a9d1cfcdbe58f208443abb1f3109f4b9b12fd60b187c"}, - {file = "zope.interface-7.0.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:84f8794bd59ca7d09d8fce43ae1b571be22f52748169d01a13d3ece8394d8b5b"}, - {file = "zope.interface-7.0.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:7d92920416f31786bc1b2f34cc4fc4263a35a407425319572cbf96b51e835cd3"}, - {file = "zope.interface-7.0.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:95e5913ec718010dc0e7c215d79a9683b4990e7026828eedfda5268e74e73e11"}, - {file = "zope.interface-7.0.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1eeeb92cb7d95c45e726e3c1afe7707919370addae7ed14f614e22217a536958"}, - {file = "zope.interface-7.0.3-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ecd32f30f40bfd8511b17666895831a51b532e93fc106bfa97f366589d3e4e0e"}, - {file = "zope.interface-7.0.3-cp39-cp39-win_amd64.whl", hash = "sha256:5112c530fa8aa2108a3196b9c2f078f5738c1c37cfc716970edc0df0414acda8"}, - {file = "zope.interface-7.0.3.tar.gz", hash = "sha256:cd2690d4b08ec9eaf47a85914fe513062b20da78d10d6d789a792c0b20307fb1"}, + {file = "zope.interface-7.1.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6650bd56ef350d37c8baccfd3ee8a0483ed6f8666e641e4b9ae1a1827b79f9e5"}, + {file = "zope.interface-7.1.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:84e87eba6b77a3af187bae82d8de1a7c208c2a04ec9f6bd444fd091b811ad92e"}, + {file = "zope.interface-7.1.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1c4e1b4c06d9abd1037c088dae1566c85f344a3e6ae4350744c3f7f7259d9c67"}, + {file = "zope.interface-7.1.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7cd5e3d910ac87652a09f6e5db8e41bc3b49cf08ddd2d73d30afc644801492cd"}, + {file = "zope.interface-7.1.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ca95594d936ee349620900be5b46c0122a1ff6ce42d7d5cb2cf09dc84071ef16"}, + {file = "zope.interface-7.1.1-cp310-cp310-win_amd64.whl", hash = "sha256:ad339509dcfbbc99bf8e147db6686249c4032f26586699ec4c82f6e5909c9fe2"}, + {file = "zope.interface-7.1.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3e59f175e868f856a77c0a77ba001385c377df2104fdbda6b9f99456a01e102a"}, + {file = "zope.interface-7.1.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:0de23bcb93401994ea00bc5c677ef06d420340ac0a4e9c10d80e047b9ce5af3f"}, + {file = "zope.interface-7.1.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5cdb7e7e5524b76d3ec037c1d81a9e2c7457b240fd4cb0a2476b65c3a5a6c81f"}, + {file = "zope.interface-7.1.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3603ef82a9920bd0bfb505423cb7e937498ad971ad5a6141841e8f76d2fd5446"}, + {file = "zope.interface-7.1.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f1d52d052355e0c5c89e0630dd2ff7c0b823fd5f56286a663e92444761b35e25"}, + {file = "zope.interface-7.1.1-cp311-cp311-win_amd64.whl", hash = "sha256:179ad46ece518c9084cb272e4a69d266b659f7f8f48e51706746c2d8a426433e"}, + {file = "zope.interface-7.1.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:e6503534b52bb1720ace9366ee30838a58a3413d3e197512f3338c8f34b5d89d"}, + {file = "zope.interface-7.1.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f85b290e5b8b11814efb0d004d8ce6c9a483c35c462e8d9bf84abb93e79fa770"}, + {file = "zope.interface-7.1.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d029fac6a80edae80f79c37e5e3abfa92968fe921886139b3ee470a1b177321a"}, + {file = "zope.interface-7.1.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5836b8fb044c6e75ba34dfaabc602493019eadfa0faf6ff25f4c4c356a71a853"}, + {file = "zope.interface-7.1.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7395f13533318f150ee72adb55b29284b16e73b6d5f02ab21f173b3e83f242b8"}, + {file = "zope.interface-7.1.1-cp312-cp312-win_amd64.whl", hash = "sha256:1d0e23c6b746eb8ce04573cc47bcac60961ac138885d207bd6f57e27a1431ae8"}, + {file = "zope.interface-7.1.1-cp313-cp313-macosx_10_9_x86_64.whl", hash = "sha256:9fad9bd5502221ab179f13ea251cb30eef7cf65023156967f86673aff54b53a0"}, + {file = "zope.interface-7.1.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:55c373becbd36a44d0c9be1d5271422fdaa8562d158fb44b4192297b3c67096c"}, + {file = "zope.interface-7.1.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ed1df8cc01dd1e3970666a7370b8bfc7457371c58ba88c57bd5bca17ab198053"}, + {file = "zope.interface-7.1.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:99c14f0727c978639139e6cad7a60e82b7720922678d75aacb90cf4ef74a068c"}, + {file = "zope.interface-7.1.1-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9b1eed7670d564f1025d7cda89f99f216c30210e42e95de466135be0b4a499d9"}, + {file = "zope.interface-7.1.1-cp313-cp313-win_amd64.whl", hash = "sha256:3defc925c4b22ac1272d544a49c6ba04c3eefcce3200319ee1be03d9270306dd"}, + {file = "zope.interface-7.1.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:8d0fe45be57b5219aa4b96e846631c04615d5ef068146de5a02ccd15c185321f"}, + {file = "zope.interface-7.1.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:bcbeb44fc16e0078b3b68a95e43f821ae34dcbf976dde6985141838a5f23dd3d"}, + {file = "zope.interface-7.1.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c8e7b05dc6315a193cceaec071cc3cf1c180cea28808ccded0b1283f1c38ba73"}, + {file = "zope.interface-7.1.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2d553e02b68c0ea5a226855f02edbc9eefd99f6a8886fa9f9bdf999d77f46585"}, + {file = "zope.interface-7.1.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:81744a7e61b598ebcf4722ac56a7a4f50502432b5b4dc7eb29075a89cf82d029"}, + {file = "zope.interface-7.1.1-cp38-cp38-win_amd64.whl", hash = "sha256:7720322763aceb5e0a7cadcc38c67b839efe599f0887cbf6c003c55b1458c501"}, + {file = "zope.interface-7.1.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:1a2ed0852c25950cf430067f058f8d98df6288502ac313861d9803fe7691a9b3"}, + {file = "zope.interface-7.1.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:9595e478047ce752b35cfa221d7601a5283ccdaab40422e0dc1d4a334c70f580"}, + {file = "zope.interface-7.1.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2317e1d4dba68203a5227ea3057f9078ec9376275f9700086b8f0ffc0b358e1b"}, + {file = "zope.interface-7.1.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d6821ef9870f32154da873fcde439274f99814ea452dd16b99fa0b66345c4b6b"}, + {file = "zope.interface-7.1.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:190eeec67e023d5aac54d183fa145db0b898664234234ac54643a441da434616"}, + {file = "zope.interface-7.1.1-cp39-cp39-win_amd64.whl", hash = "sha256:d17e7fc814eaab93409b80819fd6d30342844345c27f3bc3c4b43c2425a8d267"}, + {file = "zope.interface-7.1.1.tar.gz", hash = "sha256:4284d664ef0ff7b709836d4de7b13d80873dc5faeffc073abdb280058bfac5e3"}, ] [package.dependencies] setuptools = "*" [package.extras] -docs = ["Sphinx", "repoze.sphinx.autointerface", "sphinx-rtd-theme"] -test = ["coverage (>=5.0.3)", "zope.event", "zope.testing"] -testing = ["coverage (>=5.0.3)", "zope.event", "zope.testing"] +docs = ["Sphinx", "furo", "repoze.sphinx.autointerface"] +test = ["coverage[toml]", "zope.event", "zope.testing"] +testing = ["coverage[toml]", "zope.event", "zope.testing"] [extras] maco = ["maco"] @@ -4638,4 +4174,4 @@ maco = ["maco"] [metadata] lock-version = "2.0" python-versions = ">=3.10, <4.0" -content-hash = "ab65373ef8c8244e2d8237cb6208783a0276fa62f52545098cb12170c1cd7d76" +content-hash = "f283142fd57ad19b7a5cff077d93ffa6757dc781335284bf651d152d85a579e1" diff --git a/pyproject.toml b/pyproject.toml index 2d50b19820a..0968fee45b0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -16,22 +16,22 @@ cryptography = "43.0.1" requests = {version = "2.32.2", extras = ["security", "socks"]} # pyOpenSSL = "24.0.0" pefile = "*" -tldextract = "3.5.0" +tldextract = ">=5.1.2" oletools = "0.60" olefile = "0.46" # mixbox = "1.0.5" capstone = "4.0.2" -pycryptodomex = "3.20.0" +pycryptodomex = ">=3.20.0" # xmltodict = "0.12.0" requests-file = "1.5.1" orjson = "3.9.15" # maec = "4.1.0.17" -regex = "2021.7.6" +# regex = "2021.7.6" SFlock2 = {version = "0.3.66", extras = ["shellcode","linux"]} # volatility3 = "2.0.0" # XLMMacroDeobfuscator = "0.2.7" pyzipper = "0.3.5" -flare-capa = "7.3.0" +# flare-capa = "7.3.0" Cython = "0.29.24" # pyre2 = "0.3.6" # Dead for python3.11 Django = "4.2.16" @@ -73,7 +73,6 @@ ruff = "0.0.290" paramiko = "3.4.0" psutil = "5.9.8" # peepdf-3 = "4.0.0" -maco = "1.1.8" Werkzeug = "3.0.6" packaging = "23.1" @@ -89,10 +88,8 @@ gunicorn = "^22.0.0" channels = "^3.0.5" setproctitle = "1.3.2" -# tmp dependency to fix vuln -certifi = "2024.7.4" -rat_king_parser = {git = "https://github.com/jeFF0Falltrades/rat_king_parser", rev = "ab849ec8face38c8dac3f803ae5fe7cf8be26583"} - +CAPE-parsers = "0.1.4" +maco = "1.1.8" [tool.poetry.extras] maco = ["maco"] diff --git a/tests/test_aplib.py b/tests/test_aplib.py deleted file mode 100644 index 68299796f1f..00000000000 --- a/tests/test_aplib.py +++ /dev/null @@ -1,10 +0,0 @@ -# Copyright (C) 2010-2015 Cuckoo Foundation. -# This file is part of Cuckoo Sandbox - http://www.cuckoosandbox.org -# See the file 'docs/LICENSE' for copying permission. - -from lib.cuckoo.common import aplib - - -def test_apilib_decompress(): - data = b"T\x00he quick\xecb\x0erown\xcef\xaex\x80jumps\xed\xe4veur`t?lazy\xead\xfeg\xc0\x00" - assert aplib.decompress(data) == b"The quick brown fox jumps over the lazy dog" diff --git a/tests_parsers/readme.md b/tests_parsers/readme.md deleted file mode 100644 index d7205b55664..00000000000 --- a/tests_parsers/readme.md +++ /dev/null @@ -1,2 +0,0 @@ -* Sample goes to: - * https://github.com/CAPESandbox/CAPE-TestFiles/tree/main/malware diff --git a/tests_parsers/test_agenttesla.py b/tests_parsers/test_agenttesla.py deleted file mode 100644 index b52cd064ce6..00000000000 --- a/tests_parsers/test_agenttesla.py +++ /dev/null @@ -1,49 +0,0 @@ -from contextlib import suppress - -from modules.processing.parsers.CAPE.AgentTesla import extract_config - -HAVE_MACO = False -with suppress(ImportError): - from modules.processing.parsers.MACO.AgentTesla import convert_to_MACO - - HAVE_MACO = True - - -def test_agenttesla(): - # AgentTeslaV5 - with open("tests/data/malware/893f4dc8f8a1dcee05a0840988cf90bc93c1cda5b414f35a6adb5e9f40678ce9", "rb") as data: - conf = extract_config(data.read()) - assert conf == { - "Protocol": "SMTP", - "C2": "mail.guestequipment.com.au", - "Username": "sendlog@guestequipment.com.au", - "Password": "Clone89!", - "EmailTo": "info@marethon.com", - "Persistence_Filename": "newfile.exe", - "ExternalIPCheckServices": ["http://ip-api.com/line/?fields=hosting"], - } - - if HAVE_MACO: - assert convert_to_MACO(conf).model_dump(exclude_defaults=True, exclude_none=True) == { - "family": "AgentTesla", - "other": { - "Protocol": "SMTP", - "C2": "mail.guestequipment.com.au", - "Username": "sendlog@guestequipment.com.au", - "Password": "Clone89!", - "EmailTo": "info@marethon.com", - "Persistence_Filename": "newfile.exe", - "ExternalIPCheckServices": ["http://ip-api.com/line/?fields=hosting"], - }, - "smtp": [ - { - "username": "sendlog@guestequipment.com.au", - "password": "Clone89!", - "hostname": "mail.guestequipment.com.au", - "mail_to": ["info@marethon.com"], - "usage": "c2", - } - ], - "http": [{"uri": "http://ip-api.com/line/?fields=hosting", "usage": "other"}], - "paths": [{"path": "newfile.exe", "usage": "storage"}], - } diff --git a/tests_parsers/test_asyncrat.py b/tests_parsers/test_asyncrat.py deleted file mode 100644 index ee49867d95d..00000000000 --- a/tests_parsers/test_asyncrat.py +++ /dev/null @@ -1,44 +0,0 @@ -from contextlib import suppress - -from modules.processing.parsers.CAPE.AsyncRAT import extract_config - -HAVE_MACO = False -with suppress(ImportError): - from modules.processing.parsers.MACO.AsyncRAT import convert_to_MACO - - HAVE_MACO = True - - -def test_asyncrat(): - with open("tests/data/malware/f08b325f5322a698e14f97db29d322e9ee91ad636ac688af352d51057fc56526", "rb") as data: - conf = extract_config(data.read()) - assert conf == { - "C2s": ["todfg.duckdns.org"], - "Ports": "6745", - "Version": "0.5.7B", - "Folder": "%AppData%", - "Filename": "updateee.exe", - "Install": "false", - "Mutex": "AsyncMutex_6SI8OkPnk", - "Pastebin": "null", - } - - if HAVE_MACO: - assert convert_to_MACO(conf).model_dump(exclude_defaults=True, exclude_none=True) == { - "family": "AsyncRAT", - "version": "0.5.7B", - "capability_disabled": ["persistence"], - "mutex": ["AsyncMutex_6SI8OkPnk"], - "other": { - "C2s": ["todfg.duckdns.org"], - "Ports": "6745", - "Version": "0.5.7B", - "Folder": "%AppData%", - "Filename": "updateee.exe", - "Install": "false", - "Mutex": "AsyncMutex_6SI8OkPnk", - "Pastebin": "null", - }, - "http": [{"hostname": "todfg.duckdns.org", "port": 6, "usage": "c2"}], - "paths": [{"path": "%AppData%/updateee.exe", "usage": "install"}], - } diff --git a/tests_parsers/test_aurorastealer.py b/tests_parsers/test_aurorastealer.py deleted file mode 100644 index a09cc324614..00000000000 --- a/tests_parsers/test_aurorastealer.py +++ /dev/null @@ -1,38 +0,0 @@ -from contextlib import suppress - -from modules.processing.parsers.CAPE.AuroraStealer import extract_config - -HAVE_MACO = False -with suppress(ImportError): - from modules.processing.parsers.MACO.AuroraStealer import convert_to_MACO - - HAVE_MACO = True - - -def test_aurorastealer(): - with open("tests/data/malware/8da8821d410b94a2811ce7ae80e901d7e150ad3420d677b158e45324a6606ac4", "rb") as data: - conf = extract_config(data.read()) - assert conf == { - "BuildID": "x64pump", - "MD5Hash": "f29f33b296b35ec5e7fc3ee784ef68ee", - "C2": "77.91.85.73", - "Architecture": "X64", - "BuildGroup": "x64pump", - "BuildAccept": "0", - "Date": "2023-04-06 19", - } - - if HAVE_MACO: - assert convert_to_MACO(conf).model_dump(exclude_defaults=True, exclude_none=True) == { - "family": "AuroraStealer", - "other": { - "BuildID": "x64pump", - "MD5Hash": "f29f33b296b35ec5e7fc3ee784ef68ee", - "C2": "77.91.85.73", - "Architecture": "X64", - "BuildGroup": "x64pump", - "BuildAccept": "0", - "Date": "2023-04-06 19", - }, - "http": [{"hostname": "77.91.85.73", "usage": "c2"}], - } diff --git a/tests_parsers/test_blackdropper.py b/tests_parsers/test_blackdropper.py deleted file mode 100644 index cf8326f56cd..00000000000 --- a/tests_parsers/test_blackdropper.py +++ /dev/null @@ -1,36 +0,0 @@ -# Copyright (C) 2010-2015 Cuckoo Foundation. -# This file is part of Cuckoo Sandbox - http://www.cuckoosandbox.org -# See the file 'docs/LICENSE' for copying permission. - -from contextlib import suppress - -from modules.processing.parsers.CAPE.BlackDropper import extract_config - -HAVE_MACO = False -with suppress(ImportError): - from modules.processing.parsers.MACO.BlackDropper import convert_to_MACO - - HAVE_MACO = True - - -def test_blackdropper(): - with open("tests/data/malware/f8026ae3237bdd885e5fcaceb86bcab4087d8857e50ba472ca79ce44c12bc257", "rb") as data: - conf = extract_config(data.read()) - assert conf == { - "urls": ["http://72.5.42.222:8568/api/dll/", "http://72.5.42.222:8568/api/fileZip"], - "directories": ["\\Music\\dkcydqtwjv"], - "campaign": "oFwQ0aQ3v", - } - - if HAVE_MACO: - assert convert_to_MACO(conf).model_dump(exclude_defaults=True, exclude_none=True) == { - "family": "BlackDropper", - "campaign_id": ["oFwQ0aQ3v"], - "other": { - "urls": ["http://72.5.42.222:8568/api/dll/", "http://72.5.42.222:8568/api/fileZip"], - "directories": ["\\Music\\dkcydqtwjv"], - "campaign": "oFwQ0aQ3v", - }, - "http": [{"uri": "http://72.5.42.222:8568/api/dll/"}, {"uri": "http://72.5.42.222:8568/api/fileZip"}], - "paths": [{"path": "\\Music\\dkcydqtwjv"}], - } diff --git a/tests_parsers/test_bumblebee.py b/tests_parsers/test_bumblebee.py deleted file mode 100644 index c26509687a4..00000000000 --- a/tests_parsers/test_bumblebee.py +++ /dev/null @@ -1,28 +0,0 @@ -# Copyright (C) 2010-2015 Cuckoo Foundation. -# This file is part of Cuckoo Sandbox - http://www.cuckoosandbox.org -# See the file 'docs/LICENSE' for copying permission. - -from contextlib import suppress - -from modules.processing.parsers.CAPE.BumbleBee import extract_config - -HAVE_MACO = False -with suppress(ImportError): - from modules.processing.parsers.MACO.BumbleBee import convert_to_MACO - - HAVE_MACO = True - - -def test_bumblebee(): - with open("tests/data/malware/f8a6eddcec59934c42ea254cdd942fb62917b5898f71f0feeae6826ba4f3470d", "rb") as data: - conf = extract_config(data.read()) - assert conf == {"Botnet ID": "YTBSBbNTWU", "Campaign ID": "1904r", "Data": "XNgHUGLrCD", "C2s": ["444"]} - if HAVE_MACO: - assert convert_to_MACO(conf).model_dump(exclude_defaults=True, exclude_none=True) == { - "family": "BumbleBee", - "campaign_id": ["1904r"], - "identifier": ["YTBSBbNTWU"], - "other": {"Botnet ID": "YTBSBbNTWU", "Campaign ID": "1904r", "Data": "XNgHUGLrCD", "C2s": ["444"]}, - "binaries": [{"data": "XNgHUGLrCD"}], - "http": [{"hostname": "444", "usage": "c2"}], - } diff --git a/tests_parsers/test_carbanak.py b/tests_parsers/test_carbanak.py deleted file mode 100644 index bb0d512bccf..00000000000 --- a/tests_parsers/test_carbanak.py +++ /dev/null @@ -1,21 +0,0 @@ -from contextlib import suppress - -from modules.processing.parsers.CAPE.Carbanak import extract_config - -HAVE_MACO = False -with suppress(ImportError): - from modules.processing.parsers.MACO.Carbanak import convert_to_MACO - - HAVE_MACO = True - - -def test_carbanak(): - with open("tests/data/malware/c9c1b06cb9c9bd6fc4451f5e2847a1f9524bb2870d7bb6f0ee09b9dd4e3e4c84", "rb") as data: - conf = extract_config(data.read()) - assert conf["C2"] == ["5.161.223.210:443", "207.174.30.226:443"] - if HAVE_MACO: - assert convert_to_MACO(conf).model_dump(exclude_defaults=True, exclude_none=True) == { - "family": "Carbanak", - "other": {"C2": ["5.161.223.210:443", "207.174.30.226:443"]}, - "http": [{"hostname": "5.161.223.210:443", "usage": "c2"}, {"hostname": "207.174.30.226:443", "usage": "c2"}], - } diff --git a/tests_parsers/test_cobaltstrikebeacon.py b/tests_parsers/test_cobaltstrikebeacon.py deleted file mode 100644 index 12afcdd3677..00000000000 --- a/tests_parsers/test_cobaltstrikebeacon.py +++ /dev/null @@ -1,125 +0,0 @@ -# Copyright (C) 2010-2015 Cuckoo Foundation. -# This file is part of Cuckoo Sandbox - http://www.cuckoosandbox.org -# See the file 'docs/LICENSE' for copying permission. - -from contextlib import suppress - -from modules.processing.parsers.CAPE.CobaltStrikeBeacon import extract_config - -HAVE_MACO = False -with suppress(ImportError): - from modules.processing.parsers.MACO.CobaltStrikeBeacon import convert_to_MACO - - HAVE_MACO = True - - -def test_csb(): - with open("tests/data/malware/2588fd3232138f587e294aea5cc9a0611d1e165b199743552c84bfddc1e4c063", "rb") as data: - conf = extract_config(data.read()) - assert convert_to_MACO(conf).model_dump(exclude_defaults=True, exclude_none=True) == { - "BeaconType": ["HTTP"], - "Port": 4848, - "SleepTime": 60000, - "MaxGetSize": 1048576, - "Jitter": 0, - "MaxDNS": "Not Found", - "PublicKey": "30819f300d06092a864886f70d010101050003818d0030818902818100bebe41805d3c15a738caf3e308a992d4d507ce827996a8c9d783c766963e7e73083111729ae0abc1b49af0bcf803efdcaf83ac694fb53d043a88e9333f169e026a3c4e63cc6d4cd1aa5e199cb95eec500f948ac472c0ab2eda385d35fb8592d74b1154a1c671afb310eccb0b139ee1100907bfcdd8dfbf3385803a11bc252995020301000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "C2Server": "192.144.206.100,/load", - "UserAgent": "Not Found", - "HttpPostUri": "/submit.php", - "Malleable_C2_Instructions": [], - "HttpGet_Metadata": "Not Found", - "HttpPost_Metadata": "Not Found", - "SpawnTo": "d7a9ca15a07f82bfd3b63020da38aa16", - "PipeName": "Not Found", - "DNS_Idle": "Not Found", - "DNS_Sleep": "Not Found", - "SSH_Host": "Not Found", - "SSH_Port": "Not Found", - "SSH_Username": "Not Found", - "SSH_Password_Plaintext": "Not Found", - "SSH_Password_Pubkey": "Not Found", - "HttpGet_Verb": "GET", - "HttpPost_Verb": "POST", - "HttpPostChunk": 0, - "Spawnto_x86": "%windir%\\syswow64\\rundll32.exe", - "Spawnto_x64": "%windir%\\sysnative\\rundll32.exe", - "CryptoScheme": 0, - "Proxy_Config": "Not Found", - "Proxy_User": "Not Found", - "Proxy_Password": "Not Found", - "Proxy_Behavior": "Use IE settings", - "Watermark": 391144938, - "bStageCleanup": "False", - "bCFGCaution": "False", - "KillDate": 0, - "bProcInject_StartRWX": "True", - "bProcInject_UseRWX": "True", - "bProcInject_MinAllocSize": 0, - "ProcInject_PrependAppend_x86": "Empty", - "ProcInject_PrependAppend_x64": "Empty", - "ProcInject_Execute": ["CreateThread", "SetThreadContext", "CreateRemoteThread", "RtlCreateUserThread"], - "ProcInject_AllocationMethod": "VirtualAllocEx", - "bUsesCookies": "True", - "HostHeader": "", - } - if HAVE_MACO: - assert convert_to_MACO(conf).model_dump(exclude_defaults=True, exclude_none=True) == { - "family": "CobaltStrikeBeacon", - "capability_enabled": ["ProcInject_StartRWX", "ProcInject_UseRWX", "UsesCookies"], - "capability_disabled": ["StageCleanup", "CFGCaution"], - "sleep_delay": 60000, - "sleep_delay_jitter": 0, - "other": { - "BeaconType": ["HTTP"], - "Port": 4848, - "SleepTime": 60000, - "MaxGetSize": 1048576, - "Jitter": 0, - "MaxDNS": "Not Found", - "PublicKey": "30819f300d06092a864886f70d010101050003818d0030818902818100bebe41805d3c15a738caf3e308a992d4d507ce827996a8c9d783c766963e7e73083111729ae0abc1b49af0bcf803efdcaf83ac694fb53d043a88e9333f169e026a3c4e63cc6d4cd1aa5e199cb95eec500f948ac472c0ab2eda385d35fb8592d74b1154a1c671afb310eccb0b139ee1100907bfcdd8dfbf3385803a11bc252995020301000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "C2Server": "192.144.206.100,/load", - "UserAgent": "Not Found", - "HttpPostUri": "/submit.php", - "Malleable_C2_Instructions": [], - "HttpGet_Metadata": "Not Found", - "HttpPost_Metadata": "Not Found", - "SpawnTo": "d7a9ca15a07f82bfd3b63020da38aa16", - "PipeName": "Not Found", - "DNS_Idle": "Not Found", - "DNS_Sleep": "Not Found", - "SSH_Host": "Not Found", - "SSH_Port": "Not Found", - "SSH_Username": "Not Found", - "SSH_Password_Plaintext": "Not Found", - "SSH_Password_Pubkey": "Not Found", - "HttpGet_Verb": "GET", - "HttpPost_Verb": "POST", - "HttpPostChunk": 0, - "Spawnto_x86": "%windir%\\syswow64\\rundll32.exe", - "Spawnto_x64": "%windir%\\sysnative\\rundll32.exe", - "CryptoScheme": 0, - "Proxy_Config": "Not Found", - "Proxy_User": "Not Found", - "Proxy_Password": "Not Found", - "Proxy_Behavior": "Use IE settings", - "Watermark": 391144938, - "bStageCleanup": "False", - "bCFGCaution": "False", - "KillDate": 0, - "bProcInject_StartRWX": "True", - "bProcInject_UseRWX": "True", - "bProcInject_MinAllocSize": 0, - "ProcInject_PrependAppend_x86": "Empty", - "ProcInject_PrependAppend_x64": "Empty", - "ProcInject_Execute": ["CreateThread", "SetThreadContext", "CreateRemoteThread", "RtlCreateUserThread"], - "ProcInject_AllocationMethod": "VirtualAllocEx", - "bUsesCookies": "True", - "HostHeader": "", - }, - "http": [ - {"hostname": "192.144.206.100", "port": 4848, "path": "/load", "method": "GET", "usage": "c2"}, - {"hostname": "192.144.206.100", "port": 4848, "path": "/submit.php", "method": "POST", "usage": "c2"}, - ], - "paths": [{"path": "%windir%\\syswow64\\rundll32.exe"}, {"path": "%windir%\\sysnative\\rundll32.exe"}], - } diff --git a/tests_parsers/test_darkgate.py b/tests_parsers/test_darkgate.py deleted file mode 100644 index 7040df6f51f..00000000000 --- a/tests_parsers/test_darkgate.py +++ /dev/null @@ -1,21 +0,0 @@ -from contextlib import suppress - -from modules.processing.parsers.CAPE.DarkGate import extract_config - -HAVE_MACO = False -with suppress(ImportError): - from modules.processing.parsers.MACO.DarkGate import convert_to_MACO - - HAVE_MACO = True - - -def test_darkgate(): - with open("tests/data/malware/1c3ae64795b61034080be00601b947819fe071efd69d7fc791a99ec666c2043d", "rb") as data: - conf = extract_config(data.read()) - assert conf["C2"] == ["http://80.66.88.145"] - if HAVE_MACO: - assert convert_to_MACO(conf).model_dump(exclude_defaults=True, exclude_none=True) == { - "family": "DarkGate", - "other": {"C2": ["http://80.66.88.145"]}, - "http": [{"uri": "http://80.66.88.145", "usage": "c2"}], - } diff --git a/tests_parsers/test_icedid.py b/tests_parsers/test_icedid.py deleted file mode 100644 index 8b8b389a15d..00000000000 --- a/tests_parsers/test_icedid.py +++ /dev/null @@ -1,22 +0,0 @@ -from contextlib import suppress - -from modules.processing.parsers.CAPE.IcedIDLoader import extract_config - -HAVE_MACO = False -with suppress(ImportError): - from modules.processing.parsers.MACO.IcedIDLoader import convert_to_MACO - - HAVE_MACO = True - - -def test_icedid(): - with open("tests/data/malware/7aaf80eb1436b946b2bd710ab57d2dcbaad2b1553d45602f2f3af6f2cfca5212", "rb") as data: - conf = extract_config(data.read()) - assert conf == {"C2": "anscowerbrut.com", "Campaign": 2738000827} - if HAVE_MACO: - assert convert_to_MACO(conf).model_dump(exclude_defaults=True, exclude_none=True) == { - "family": "IcedIDLoader", - "campaign_id": ["2738000827"], - "other": {"C2": "anscowerbrut.com", "Campaign": 2738000827}, - "http": [{"hostname": "anscowerbrut.com", "usage": "c2"}], - } diff --git a/tests_parsers/test_koiloader.py b/tests_parsers/test_koiloader.py deleted file mode 100644 index 38a74bf700a..00000000000 --- a/tests_parsers/test_koiloader.py +++ /dev/null @@ -1,28 +0,0 @@ -# Copyright (C) 2010-2015 Cuckoo Foundation. -# This file is part of Cuckoo Sandbox - http://www.cuckoosandbox.org -# See the file 'docs/LICENSE' for copying permission. - -from contextlib import suppress - -from modules.processing.parsers.CAPE.KoiLoader import extract_config - -HAVE_MACO = False -with suppress(ImportError): - from modules.processing.parsers.MACO.KoiLoader import convert_to_MACO - - HAVE_MACO = True - - -def test_koiloader(): - with open("tests/data/malware/b462e3235c7578450b2b56a8aff875a3d99d22f6970a01db3ba98f7ecb6b01a0", "rb") as data: - conf = extract_config(data.read()) - assert conf == {"C2": ["http://91.202.233.209/hypermetropia.php", "https://admiralpub.ca/wp-content/uploads/2017"]} - if HAVE_MACO: - assert convert_to_MACO(conf).model_dump(exclude_defaults=True, exclude_none=True) == { - "family": "KoiLoader", - "other": {"C2": ["http://91.202.233.209/hypermetropia.php", "https://admiralpub.ca/wp-content/uploads/2017"]}, - "http": [ - {"uri": "http://91.202.233.209/hypermetropia.php", "usage": "c2"}, - {"uri": "https://admiralpub.ca/wp-content/uploads/2017", "usage": "c2"}, - ], - } diff --git a/tests_parsers/test_latrodectus.py b/tests_parsers/test_latrodectus.py deleted file mode 100644 index 410bac0a9e2..00000000000 --- a/tests_parsers/test_latrodectus.py +++ /dev/null @@ -1,293 +0,0 @@ -# Copyright (C) 2010-2015 Cuckoo Foundation. -# This file is part of Cuckoo Sandbox - http://www.cuckoosandbox.org -# See the file 'docs/LICENSE' for copying permission. - -from contextlib import suppress - -from modules.processing.parsers.CAPE.Latrodectus import extract_config - -HAVE_MACO = False -with suppress(ImportError): - from modules.processing.parsers.MACO.Latrodectus import convert_to_MACO - - HAVE_MACO = True - - -def test_latrodectus(): - with open("tests/data/malware/a547cff9991a713535e5c128a0711ca68acf9298cc2220c4ea0685d580f36811", "rb") as data: - conf = extract_config(data.read()) - assert conf == { - "C2": ["https://arsimonopa.com/live/", "https://lemonimonakio.com/live/"], - "Group name": "Novik", - "Campaign ID": 1053565364, - "Version": "1.1", - "RC4 key": "12345", - "Strings": [ - "/c ipconfig /all", - "C:\\Windows\\System32\\cmd.exe", - "/c systeminfo", - "C:\\Windows\\System32\\cmd.exe", - "/c nltest /domain_trusts", - "C:\\Windows\\System32\\cmd.exe", - "/c nltest /domain_trusts /all_trusts", - "C:\\Windows\\System32\\cmd.exe", - "/c net view /all /domain", - "C:\\Windows\\System32\\cmd.exe", - "/c net view /all", - "C:\\Windows\\System32\\cmd.exe", - '/c net group "Domain Admins" /domain', - "C:\\Windows\\System32\\cmd.exe", - "/Node:localhost /Namespace:\\\\root\\SecurityCenter2 Path AntiVirusProduct Get * /Format:List", - "C:\\Windows\\System32\\wbem\\wmic.exe", - "/c net config workstation", - "C:\\Windows\\System32\\cmd.exe", - "/c wmic.exe /node:localhost /namespace:\\\\root\\SecurityCenter2 path AntiVirusProduct Get DisplayName | findstr /V /B /C:displayName || echo No Antivirus installed", - "C:\\Windows\\System32\\cmd.exe", - "/c whoami /groups", - "C:\\Windows\\System32\\cmd.exe", - ".dll", - ".exe", - '"%s"', - "rundll32.exe", - '"%s", %s %s', - "runnung", - ":wtfbbq", - "%s%s", - "%s\\%d.dll", - "%d.dat", - "%s\\%s", - 'init -zzzz="%s\\%s"', - "front", - "/files/", - "Novik", - ".exe", - "Content-Type: application/x-www-form-urlencoded", - "POST", - "GET", - "curl/7.88.1", - "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Tob 1.1)", - "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Tob 1.1)", - "CLEARURL", - "URLS", - "COMMAND", - "ERROR", - "12345", - "counter=%d&type=%d&guid=%s&os=%d&arch=%d&username=%s&group=%lu&ver=%d.%d&up=%d&direction=%s", - "counter=%d&type=%d&guid=%s&os=%d&arch=%d&username=%s&group=%lu&ver=%d.%d&up=%d&direction=%s", - "counter=%d&type=%d&guid=%s&os=%d&arch=%d&username=%s&group=%lu&ver=%d.%d&up=%d&direction=%s", - "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Tob 1.1)", - "%s%d.dll", - "%s%d.exe", - "LogonTrigger", - "%x%x", - "TimeTrigger", - "PT1H%02dM", - "&mac=", - "%04d-%02d-%02dT%02d:%02d:%02d", - "%02x", - ":%02x", - "PT0S", - "&computername=%s", - "&domain=%s", - "\\*.dll", - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/", - "%04X%04X%04X%04X%08X%04X", - "%04X%04X%04X%04X%08X%04X", - "\\Registry\\Machine\\", - "AppData", - "Desktop", - "Startup", - "Personal", - "Local AppData", - "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders", - "C:\\WINDOWS\\SYSTEM32\\rundll32.exe %s,%s", - "C:\\WINDOWS\\SYSTEM32\\rundll32.exe %s", - "URLS", - "URLS|%d|%s\r\n", - ], - } - if HAVE_MACO: - assert convert_to_MACO(conf).model_dump(exclude_defaults=True, exclude_none=True) == { - "family": "Latrodectus", - "version": "1.1", - "campaign_id": ["1053565364"], - "identifier": ["Novik"], - "decoded_strings": [ - "/c ipconfig /all", - "C:\\Windows\\System32\\cmd.exe", - "/c systeminfo", - "C:\\Windows\\System32\\cmd.exe", - "/c nltest /domain_trusts", - "C:\\Windows\\System32\\cmd.exe", - "/c nltest /domain_trusts /all_trusts", - "C:\\Windows\\System32\\cmd.exe", - "/c net view /all /domain", - "C:\\Windows\\System32\\cmd.exe", - "/c net view /all", - "C:\\Windows\\System32\\cmd.exe", - '/c net group "Domain Admins" /domain', - "C:\\Windows\\System32\\cmd.exe", - "/Node:localhost /Namespace:\\\\root\\SecurityCenter2 Path AntiVirusProduct Get * /Format:List", - "C:\\Windows\\System32\\wbem\\wmic.exe", - "/c net config workstation", - "C:\\Windows\\System32\\cmd.exe", - "/c wmic.exe /node:localhost /namespace:\\\\root\\SecurityCenter2 path AntiVirusProduct Get DisplayName | findstr /V /B /C:displayName || echo No Antivirus installed", - "C:\\Windows\\System32\\cmd.exe", - "/c whoami /groups", - "C:\\Windows\\System32\\cmd.exe", - ".dll", - ".exe", - '"%s"', - "rundll32.exe", - '"%s", %s %s', - "runnung", - ":wtfbbq", - "%s%s", - "%s\\%d.dll", - "%d.dat", - "%s\\%s", - 'init -zzzz="%s\\%s"', - "front", - "/files/", - "Novik", - ".exe", - "Content-Type: application/x-www-form-urlencoded", - "POST", - "GET", - "curl/7.88.1", - "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Tob 1.1)", - "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Tob 1.1)", - "CLEARURL", - "URLS", - "COMMAND", - "ERROR", - "12345", - "counter=%d&type=%d&guid=%s&os=%d&arch=%d&username=%s&group=%lu&ver=%d.%d&up=%d&direction=%s", - "counter=%d&type=%d&guid=%s&os=%d&arch=%d&username=%s&group=%lu&ver=%d.%d&up=%d&direction=%s", - "counter=%d&type=%d&guid=%s&os=%d&arch=%d&username=%s&group=%lu&ver=%d.%d&up=%d&direction=%s", - "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Tob 1.1)", - "%s%d.dll", - "%s%d.exe", - "LogonTrigger", - "%x%x", - "TimeTrigger", - "PT1H%02dM", - "&mac=", - "%04d-%02d-%02dT%02d:%02d:%02d", - "%02x", - ":%02x", - "PT0S", - "&computername=%s", - "&domain=%s", - "\\*.dll", - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/", - "%04X%04X%04X%04X%08X%04X", - "%04X%04X%04X%04X%08X%04X", - "\\Registry\\Machine\\", - "AppData", - "Desktop", - "Startup", - "Personal", - "Local AppData", - "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders", - "C:\\WINDOWS\\SYSTEM32\\rundll32.exe %s,%s", - "C:\\WINDOWS\\SYSTEM32\\rundll32.exe %s", - "URLS", - "URLS|%d|%s\r\n", - ], - "other": { - "C2": ["https://arsimonopa.com/live/", "https://lemonimonakio.com/live/"], - "Group name": "Novik", - "Campaign ID": 1053565364, - "Version": "1.1", - "RC4 key": "12345", - "Strings": [ - "/c ipconfig /all", - "C:\\Windows\\System32\\cmd.exe", - "/c systeminfo", - "C:\\Windows\\System32\\cmd.exe", - "/c nltest /domain_trusts", - "C:\\Windows\\System32\\cmd.exe", - "/c nltest /domain_trusts /all_trusts", - "C:\\Windows\\System32\\cmd.exe", - "/c net view /all /domain", - "C:\\Windows\\System32\\cmd.exe", - "/c net view /all", - "C:\\Windows\\System32\\cmd.exe", - '/c net group "Domain Admins" /domain', - "C:\\Windows\\System32\\cmd.exe", - "/Node:localhost /Namespace:\\\\root\\SecurityCenter2 Path AntiVirusProduct Get * /Format:List", - "C:\\Windows\\System32\\wbem\\wmic.exe", - "/c net config workstation", - "C:\\Windows\\System32\\cmd.exe", - "/c wmic.exe /node:localhost /namespace:\\\\root\\SecurityCenter2 path AntiVirusProduct Get DisplayName | findstr /V /B /C:displayName || echo No Antivirus installed", - "C:\\Windows\\System32\\cmd.exe", - "/c whoami /groups", - "C:\\Windows\\System32\\cmd.exe", - ".dll", - ".exe", - '"%s"', - "rundll32.exe", - '"%s", %s %s', - "runnung", - ":wtfbbq", - "%s%s", - "%s\\%d.dll", - "%d.dat", - "%s\\%s", - 'init -zzzz="%s\\%s"', - "front", - "/files/", - "Novik", - ".exe", - "Content-Type: application/x-www-form-urlencoded", - "POST", - "GET", - "curl/7.88.1", - "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Tob 1.1)", - "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Tob 1.1)", - "CLEARURL", - "URLS", - "COMMAND", - "ERROR", - "12345", - "counter=%d&type=%d&guid=%s&os=%d&arch=%d&username=%s&group=%lu&ver=%d.%d&up=%d&direction=%s", - "counter=%d&type=%d&guid=%s&os=%d&arch=%d&username=%s&group=%lu&ver=%d.%d&up=%d&direction=%s", - "counter=%d&type=%d&guid=%s&os=%d&arch=%d&username=%s&group=%lu&ver=%d.%d&up=%d&direction=%s", - "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Tob 1.1)", - "%s%d.dll", - "%s%d.exe", - "LogonTrigger", - "%x%x", - "TimeTrigger", - "PT1H%02dM", - "&mac=", - "%04d-%02d-%02dT%02d:%02d:%02d", - "%02x", - ":%02x", - "PT0S", - "&computername=%s", - "&domain=%s", - "\\*.dll", - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/", - "%04X%04X%04X%04X%08X%04X", - "%04X%04X%04X%04X%08X%04X", - "\\Registry\\Machine\\", - "AppData", - "Desktop", - "Startup", - "Personal", - "Local AppData", - "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders", - "C:\\WINDOWS\\SYSTEM32\\rundll32.exe %s,%s", - "C:\\WINDOWS\\SYSTEM32\\rundll32.exe %s", - "URLS", - "URLS|%d|%s\r\n", - ], - }, - "http": [ - {"uri": "https://arsimonopa.com/live/", "usage": "c2"}, - {"uri": "https://lemonimonakio.com/live/", "usage": "c2"}, - ], - "encryption": [{"algorithm": "RC4", "key": "12345"}], - } diff --git a/tests_parsers/test_lumma.py b/tests_parsers/test_lumma.py deleted file mode 100644 index e341169bcdd..00000000000 --- a/tests_parsers/test_lumma.py +++ /dev/null @@ -1,59 +0,0 @@ -# Copyright (C) 2010-2015 Cuckoo Foundation. -# This file is part of Cuckoo Sandbox - http://www.cuckoosandbox.org -# See the file 'docs/LICENSE' for copying permission. - -from contextlib import suppress - -from modules.processing.parsers.CAPE.Lumma import extract_config - -HAVE_MACO = False -with suppress(ImportError): - from modules.processing.parsers.MACO.Lumma import convert_to_MACO - - HAVE_MACO = True - - -def test_lumma(): - with open("tests/data/malware/5d58bc449693815f6fb0755a364c4cd3a8e2a81188e431d4801f2fb0b1c2de8f", "rb") as data: - conf = extract_config(data.read()) - assert conf == { - "C2": [ - "delaylacedmn.site", - "writekdmsnu.site", - "agentyanlark.site", - "bellykmrebk.site", - "underlinemdsj.site", - "commandejorsk.site", - "possiwreeste.site", - "famikyjdiag.site", - "agentyanlark.site", - ] - } - if HAVE_MACO: - assert convert_to_MACO(conf).model_dump(exclude_defaults=True, exclude_none=True) == { - "family": "Lumma", - "other": { - "C2": [ - "delaylacedmn.site", - "writekdmsnu.site", - "agentyanlark.site", - "bellykmrebk.site", - "underlinemdsj.site", - "commandejorsk.site", - "possiwreeste.site", - "famikyjdiag.site", - "agentyanlark.site", - ] - }, - "http": [ - {"hostname": "delaylacedmn.site", "usage": "c2"}, - {"hostname": "writekdmsnu.site", "usage": "c2"}, - {"hostname": "agentyanlark.site", "usage": "c2"}, - {"hostname": "bellykmrebk.site", "usage": "c2"}, - {"hostname": "underlinemdsj.site", "usage": "c2"}, - {"hostname": "commandejorsk.site", "usage": "c2"}, - {"hostname": "possiwreeste.site", "usage": "c2"}, - {"hostname": "famikyjdiag.site", "usage": "c2"}, - {"hostname": "agentyanlark.site", "usage": "c2"}, - ], - } diff --git a/tests_parsers/test_nanocore.py b/tests_parsers/test_nanocore.py deleted file mode 100644 index af28b87d8ae..00000000000 --- a/tests_parsers/test_nanocore.py +++ /dev/null @@ -1,108 +0,0 @@ -# Copyright (C) 2010-2015 Cuckoo Foundation. -# This file is part of Cuckoo Sandbox - http://www.cuckoosandbox.org -# See the file 'docs/LICENSE' for copying permission. - -from contextlib import suppress - -from modules.processing.parsers.CAPE.NanoCore import extract_config - -HAVE_MACO = False -with suppress(ImportError): - from modules.processing.parsers.MACO.NanoCore import convert_to_MACO - - HAVE_MACO = True - - -def test_nanocore(): - with open("tests/data/malware/f1bd511b69f95c26f489157272884a12225c1cf7a453207bfc46ce48a91eae96", "rb") as data: - conf = extract_config(data.read()) - assert conf == { - "BuildTime": "2023-11-22 00:25:26.569697", - "Version": "1.2.2.0", - "Mutex": "dc5ce709-95b6-4a26-9175-16a1a8446828", - "DefaultGroup": "6coinc", - "PrimaryConnectionHost": "6coinc.zapto.org", - "BackupConnectionHost": "127.0.0.1", - "ConnectionPort": "6696", - "RunOnStartup": "True", - "RequestElevation": "False", - "BypassUserAccountControl": "True", - "ClearZoneIdentifier": "True", - "ClearAccessControl": "False", - "SetCriticalProcess": "False", - "PreventSystemSleep": "True", - "ActivateAwayMode": "False", - "EnableDebugMode": "False", - "RunDelay": "0", - "ConnectDelay": "4000", - "RestartDelay": "5000", - "TimeoutInterval": "5000", - "KeepAliveTimeout": "30000", - "MutexTimeout": "5000", - "LanTimeout": "2500", - "WanTimeout": "8000", - "BufferSize": "65535", - "MaxPacketSize": "10485760", - "GCThreshold": "10485760", - "UseCustomDnsServer": "True", - "PrimaryDnsServer": "8.8.8.8", - "BackupDnsServer": "8.8.4.4", - "cncs": ["6coinc.zapto.org:6696", "127.0.0.1:6696"], - } - if HAVE_MACO: - assert convert_to_MACO(conf).model_dump(exclude_defaults=True, exclude_none=True) == { - "family": "NanoCore", - "version": "1.2.2.0", - "capability_enabled": [ - "RunOnStartup", - "BypassUserAccountControl", - "ClearZoneIdentifier", - "PreventSystemSleep", - "UseCustomDnsServer", - ], - "capability_disabled": [ - "RequestElevation", - "ClearAccessControl", - "SetCriticalProcess", - "ActivateAwayMode", - "EnableDebugMode", - ], - "mutex": ["dc5ce709-95b6-4a26-9175-16a1a8446828"], - "other": { - "BuildTime": "2023-11-22 00:25:26.569697", - "Version": "1.2.2.0", - "Mutex": "dc5ce709-95b6-4a26-9175-16a1a8446828", - "DefaultGroup": "6coinc", - "PrimaryConnectionHost": "6coinc.zapto.org", - "BackupConnectionHost": "127.0.0.1", - "ConnectionPort": "6696", - "RunOnStartup": "True", - "RequestElevation": "False", - "BypassUserAccountControl": "True", - "ClearZoneIdentifier": "True", - "ClearAccessControl": "False", - "SetCriticalProcess": "False", - "PreventSystemSleep": "True", - "ActivateAwayMode": "False", - "EnableDebugMode": "False", - "RunDelay": "0", - "ConnectDelay": "4000", - "RestartDelay": "5000", - "TimeoutInterval": "5000", - "KeepAliveTimeout": "30000", - "MutexTimeout": "5000", - "LanTimeout": "2500", - "WanTimeout": "8000", - "BufferSize": "65535", - "MaxPacketSize": "10485760", - "GCThreshold": "10485760", - "UseCustomDnsServer": "True", - "PrimaryDnsServer": "8.8.8.8", - "BackupDnsServer": "8.8.4.4", - "cncs": ["6coinc.zapto.org:6696", "127.0.0.1:6696"], - }, - "http": [ - {"hostname": "6coinc.zapto.org", "port": 6696, "usage": "c2"}, - {"hostname": "127.0.0.1", "port": 6696, "usage": "c2"}, - ], - } diff --git a/tests_parsers/test_njrat.py b/tests_parsers/test_njrat.py deleted file mode 100644 index 106d9dd1662..00000000000 --- a/tests_parsers/test_njrat.py +++ /dev/null @@ -1,63 +0,0 @@ -# Copyright (C) 2010-2015 Cuckoo Foundation. -# This file is part of Cuckoo Sandbox - http://www.cuckoosandbox.org -# See the file 'docs/LICENSE' for copying permission. - -from contextlib import suppress - -from modules.processing.parsers.CAPE.Njrat import extract_config - -HAVE_MACO = False -with suppress(ImportError): - from modules.processing.parsers.MACO.Njrat import convert_to_MACO - - HAVE_MACO = True - - -def test_njrat(): - with open("tests/data/malware/09bf19c00f3d8c63b8896edadd4622724a01f7d74de583733ee57a7d11eacd86", "rb") as data: - conf = extract_config(data.read()) - assert conf == { - "cncs": ["peter-bikini.gl.at.ply.gg:64215"], - "campaign id": "HacKed", - "version": "Njrat 0.7 Golden By Hassan Amiri", - } - if HAVE_MACO: - assert convert_to_MACO(conf).model_dump(exclude_defaults=True, exclude_none=True) == { - "family": "Njrat", - "version": "Njrat 0.7 Golden By Hassan Amiri", - "other": { - "cncs": ["peter-bikini.gl.at.ply.gg:64215"], - "campaign id": "HacKed", - "version": "Njrat 0.7 Golden By Hassan Amiri", - }, - "http": [{"hostname": "peter-bikini.gl.at.ply.gg", "port": 64215, "usage": "c2"}], - } - - -""" -https://github.com/kevoreilly/CAPEv2/pull/1957 - -09bf19c00f3d8c63b8896edadd4622724a01f7d74de583733ee57a7d11eacd86 -2a5eb2f4bb25b89a9c3d325d893b87ed58fe87a6ada67c24f7cdef54b2138567 -2e18a6a4b191741e57d8fb63bddb498f769344130e0f658d8ef5d74bd95c5c9b -4c8198288b00c70aeb7c9fcaae179873c618c1d5a804d36a54ac6e5c7fbacee2 -4e1a8dff073c5648dbeaf55a6b3320461bcb0252cee9f8f5624f46e6d05b6584 -55acd192c7cca3e46b8d1c0a24f98259ae093762722de3493a7da248e83ec07c -59f0979f3123e02ee0a13e3afa6b45d27b2fdbae75edc339d57d473d340851d8 -5b147e624ad96d036c27aa9f526ed2e7daa9ca7bfe6639404dc8e71e1177a145 -614b15eaa2b19e4f9ddb26639dbf5574126f552ae48afd7899a77bd6c7b8980d -646ed3f6856f58b90b4641ab24cdd1b6f9860b44243dfeaec952df7f0954b18a -710507e1f3e61b7010a445728b3c414efe068e22cac28c1dd3b8db56968262d7 -77d1fcf6f8bea79cac80e284a9a5dbcc36b8b57eb86c9b74c538107d4baa2c1a -8b1b215f6a6f9881bc2b76ab409b0dff080dca31c538147a9d273ba7d05919e9 -a4e7f6de5b6c1514b5a4e3361191624127320bcff249ad16207ce79644ffb9c1 -a6c954599bf0b6a3f4e5b1d8bed604a09d1115a6b35b7e9a6de66f11a9977b81 -aeece6134d1a1f0789c8c35d2541164ebc6f23511e2d6781497a82e1bec73abd -af2d5ae5ed7a72a3fa6a36cda93e163b84d8ad70a78afb08bcd1afa63d54f61e -bb7efdb9cb3673c1768a0681989e2662d3f9683b45aded8f5b780a3310bec1bb -c2c788ce1d3e55537c75684ceb961c01d9d9d0eb6b69c915c58433943320ffe5 -e5967d1012f24bad8914ecfbc79af2211ef491a4a16e2ac390d7d26089c5307a -e69befafb01863bce3c730481fa21ff8e57c72351eec8002154538fe01e3cc9e -e8636547c991ba1557cf0532a143ad2316427e773bcbe474a60d8ba2bcf3cea3 -f45abfb1e4d789528a7ce1469255a249a6cdf010045868992689d28c2b791719 -""" diff --git a/tests_parsers/test_oyster.py b/tests_parsers/test_oyster.py deleted file mode 100644 index 85811e2f80e..00000000000 --- a/tests_parsers/test_oyster.py +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright (C) 2010-2015 Cuckoo Foundation. -# This file is part of Cuckoo Sandbox - http://www.cuckoosandbox.org -# See the file 'docs/LICENSE' for copying permission. - -from contextlib import suppress - -from modules.processing.parsers.CAPE.Oyster import extract_config - -HAVE_MACO = False -with suppress(ImportError): - from modules.processing.parsers.MACO.Oyster import convert_to_MACO - - HAVE_MACO = True - - -def test_oyster(): - with open("tests/data/malware/8bae0fa9f589cd434a689eebd7a1fde949cc09e6a65e1b56bb620998246a1650", "rb") as data: - conf = extract_config(data.read()) - assert conf == { - "C2": ["https://connectivity-check.linkpc.net/"], - "Dll Version": "v1.0 #ads 2", - "Strings": ["api/connect", "Content-Type: application/json", "api/session"], - } - if HAVE_MACO: - assert convert_to_MACO(conf).model_dump(exclude_defaults=True, exclude_none=True) == { - "family": "Oyster", - "version": "v1.0 #ads 2", - "decoded_strings": ["api/connect", "Content-Type: application/json", "api/session"], - "other": { - "C2": ["https://connectivity-check.linkpc.net/"], - "Dll Version": "v1.0 #ads 2", - "Strings": ["api/connect", "Content-Type: application/json", "api/session"], - }, - "http": [{"uri": "https://connectivity-check.linkpc.net/", "usage": "c2"}], - } diff --git a/tests_parsers/test_pikabot.py b/tests_parsers/test_pikabot.py deleted file mode 100644 index 52d38194e55..00000000000 --- a/tests_parsers/test_pikabot.py +++ /dev/null @@ -1,120 +0,0 @@ -# Copyright (C) 2010-2015 Cuckoo Foundation. -# This file is part of Cuckoo Sandbox - http://www.cuckoosandbox.org -# See the file 'docs/LICENSE' for copying permission. - -from contextlib import suppress - -from modules.processing.parsers.CAPE.PikaBot import extract_config - -HAVE_MACO = False -with suppress(ImportError): - from modules.processing.parsers.MACO.PikaBot import convert_to_MACO - - HAVE_MACO = True - - -def test_pikabot(): - with open("tests/data/malware/7600d0efc92ecef06320a1a6ffd85cd90d3d98470a381b03202e81d93bcdd03c", "rb") as data: - conf = extract_config(data.read()) - assert conf == { - "C2s": [ - "154.53.55.165:13783", - "158.247.240.58:5632", - "70.34.223.164:5000", - "70.34.199.64:9785", - "45.77.63.237:5632", - "198.38.94.213:2224", - "94.72.104.80:5000", - "84.46.240.42:2083", - "154.12.236.248:13786", - "94.72.104.77:13724", - "209.126.86.48:1194", - ], - "Version": "1.8.32-beta", - "User Agent": "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; Trident/7.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E; A7F; BRI/2; Tablet PC 2.0; wbx 1.0.0; Microsoft Outlook 14.0.7233; ms-office;", - "Campaign Name": "GG24_T@T@f0adda360d2b4ccda11468e026526576", - "Registry Key": "MWnkl", - } - if HAVE_MACO: - assert convert_to_MACO(conf).model_dump(exclude_defaults=True, exclude_none=True) == { - "family": "PikaBot", - "version": "1.8.32-beta", - "campaign_id": ["GG24_T@T@f0adda360d2b4ccda11468e026526576"], - "other": { - "C2s": [ - "154.53.55.165:13783", - "158.247.240.58:5632", - "70.34.223.164:5000", - "70.34.199.64:9785", - "45.77.63.237:5632", - "198.38.94.213:2224", - "94.72.104.80:5000", - "84.46.240.42:2083", - "154.12.236.248:13786", - "94.72.104.77:13724", - "209.126.86.48:1194", - ], - "Version": "1.8.32-beta", - "User Agent": "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; Trident/7.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E; A7F; BRI/2; Tablet PC 2.0; wbx 1.0.0; Microsoft Outlook 14.0.7233; ms-office;", - "Campaign Name": "GG24_T@T@f0adda360d2b4ccda11468e026526576", - "Registry Key": "MWnkl", - }, - "http": [ - { - "hostname": "154.53.55.165", - "port": 13783, - "user_agent": "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; Trident/7.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E; A7F; BRI/2; Tablet PC 2.0; wbx 1.0.0; Microsoft Outlook 14.0.7233; ms-office;", - }, - { - "hostname": "158.247.240.58", - "port": 5632, - "user_agent": "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; Trident/7.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E; A7F; BRI/2; Tablet PC 2.0; wbx 1.0.0; Microsoft Outlook 14.0.7233; ms-office;", - }, - { - "hostname": "70.34.223.164", - "port": 5000, - "user_agent": "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; Trident/7.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E; A7F; BRI/2; Tablet PC 2.0; wbx 1.0.0; Microsoft Outlook 14.0.7233; ms-office;", - }, - { - "hostname": "70.34.199.64", - "port": 9785, - "user_agent": "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; Trident/7.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E; A7F; BRI/2; Tablet PC 2.0; wbx 1.0.0; Microsoft Outlook 14.0.7233; ms-office;", - }, - { - "hostname": "45.77.63.237", - "port": 5632, - "user_agent": "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; Trident/7.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E; A7F; BRI/2; Tablet PC 2.0; wbx 1.0.0; Microsoft Outlook 14.0.7233; ms-office;", - }, - { - "hostname": "198.38.94.213", - "port": 2224, - "user_agent": "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; Trident/7.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E; A7F; BRI/2; Tablet PC 2.0; wbx 1.0.0; Microsoft Outlook 14.0.7233; ms-office;", - }, - { - "hostname": "94.72.104.80", - "port": 5000, - "user_agent": "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; Trident/7.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E; A7F; BRI/2; Tablet PC 2.0; wbx 1.0.0; Microsoft Outlook 14.0.7233; ms-office;", - }, - { - "hostname": "84.46.240.42", - "port": 2083, - "user_agent": "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; Trident/7.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E; A7F; BRI/2; Tablet PC 2.0; wbx 1.0.0; Microsoft Outlook 14.0.7233; ms-office;", - }, - { - "hostname": "154.12.236.248", - "port": 13786, - "user_agent": "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; Trident/7.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E; A7F; BRI/2; Tablet PC 2.0; wbx 1.0.0; Microsoft Outlook 14.0.7233; ms-office;", - }, - { - "hostname": "94.72.104.77", - "port": 13724, - "user_agent": "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; Trident/7.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E; A7F; BRI/2; Tablet PC 2.0; wbx 1.0.0; Microsoft Outlook 14.0.7233; ms-office;", - }, - { - "hostname": "209.126.86.48", - "port": 1194, - "user_agent": "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; Trident/7.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E; A7F; BRI/2; Tablet PC 2.0; wbx 1.0.0; Microsoft Outlook 14.0.7233; ms-office;", - }, - ], - "registry": [{"key": "MWnkl"}], - } diff --git a/tests_parsers/test_qakbot.py b/tests_parsers/test_qakbot.py deleted file mode 100644 index fe5765baf78..00000000000 --- a/tests_parsers/test_qakbot.py +++ /dev/null @@ -1,10 +0,0 @@ -import pytest - -from modules.processing.parsers.CAPE.QakBot import extract_config - - -@pytest.mark.skip(reason="Missed file") -def test_qakbot(): - with open("tests/data/malware/0cb0d77ac38df36fff891e072dea96401a8c1e8ff40d6ac741d5a2942aaeddbb", "rb") as data: - conf = extract_config(data.read()) - assert conf == {"C2": "anscowerbrut.com", "Campaign": 2738000827} diff --git a/tests_parsers/test_quickbind.py b/tests_parsers/test_quickbind.py deleted file mode 100644 index 094790ff831..00000000000 --- a/tests_parsers/test_quickbind.py +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright (C) 2010-2015 Cuckoo Foundation. -# This file is part of Cuckoo Sandbox - http://www.cuckoosandbox.org -# See the file 'docs/LICENSE' for copying permission. - -from contextlib import suppress - -from modules.processing.parsers.CAPE.Quickbind import extract_config - -HAVE_MACO = False -with suppress(ImportError): - from modules.processing.parsers.MACO.Quickbind import convert_to_MACO - - HAVE_MACO = True - - -def test_quickbind(): - with open("tests/data/malware/bfcb215f86fc4f8b4829f6ddd5acb118e80fb5bd977453fc7e8ef10a52fc83b7", "rb") as data: - conf = extract_config(data.read()) - assert conf == { - "Encryption Key": "24de21a8dc08434c", - "Mutex": ["15432a4d-34ca-4d0d-a4ac-04df9a373862"], - "C2": ["185.49.69.41"], - } - if HAVE_MACO: - assert convert_to_MACO(conf).model_dump(exclude_defaults=True, exclude_none=True) == { - "family": "Quickbind", - "mutex": ["15432a4d-34ca-4d0d-a4ac-04df9a373862"], - "other": { - "Encryption Key": "24de21a8dc08434c", - "Mutex": ["15432a4d-34ca-4d0d-a4ac-04df9a373862"], - "C2": ["185.49.69.41"], - }, - "http": [{"hostname": "185.49.69.41", "usage": "c2"}], - "encryption": [{"key": "24de21a8dc08434c"}], - } diff --git a/tests_parsers/test_redline.py b/tests_parsers/test_redline.py deleted file mode 100644 index 8c455d06bac..00000000000 --- a/tests_parsers/test_redline.py +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright (C) 2010-2015 Cuckoo Foundation. -# This file is part of Cuckoo Sandbox - http://www.cuckoosandbox.org -# See the file "docs/LICENSE" for copying permission. - -from contextlib import suppress - -from modules.processing.parsers.CAPE.RedLine import extract_config - -HAVE_MACO = False -with suppress(ImportError): - from modules.processing.parsers.MACO.RedLine import convert_to_MACO - - HAVE_MACO = True - - -def test_redline(): - with open("tests/data/malware/000608d875638ba7d6c467ece976c1496e6a6ec8ce3e7f79e0fd195ae3045078", "rb") as data: - conf = extract_config(data.read()) - assert conf == { - "Authorization": "9059ea331e4599de3746df73ccb24514", - "C2": "77.91.68.68:19071", - "Botnet": "krast", - "Key": "Formative", - } - if HAVE_MACO: - assert convert_to_MACO(conf).model_dump(exclude_defaults=True, exclude_none=True) == { - "family": "RedLine", - "other": { - "Authorization": "9059ea331e4599de3746df73ccb24514", - "C2": "77.91.68.68:19071", - "Botnet": "krast", - "Key": "Formative", - }, - "http": [{"hostname": "77.91.68.68", "port": 19071, "usage": "c2"}], - } diff --git a/tests_parsers/test_smokeloader.py b/tests_parsers/test_smokeloader.py deleted file mode 100644 index 216829dcd94..00000000000 --- a/tests_parsers/test_smokeloader.py +++ /dev/null @@ -1,24 +0,0 @@ -from contextlib import suppress - -from modules.processing.parsers.CAPE.SmokeLoader import extract_config - -HAVE_MACO = False -with suppress(ImportError): - from modules.processing.parsers.MACO.SmokeLoader import convert_to_MACO - - HAVE_MACO = True - - -def test_smokeloader(): - with open("tests/data/malware/6929fff132c05ae7d348867f4ea77ba18f84fb8fae17d45dde3571c9e33f01f8", "rb") as data: - conf = extract_config(data.read()) - assert conf == {"C2s": ["http://host-file-host6.com/", "http://host-host-file8.com/"]} - if HAVE_MACO: - assert convert_to_MACO(conf).model_dump(exclude_defaults=True, exclude_none=True) == { - "family": "SmokeLoader", - "other": {"C2s": ["http://host-file-host6.com/", "http://host-host-file8.com/"]}, - "http": [ - {"uri": "http://host-file-host6.com/", "usage": "c2"}, - {"uri": "http://host-host-file8.com/", "usage": "c2"}, - ], - } diff --git a/tests_parsers/test_snake.py b/tests_parsers/test_snake.py deleted file mode 100644 index 489418eca86..00000000000 --- a/tests_parsers/test_snake.py +++ /dev/null @@ -1,14 +0,0 @@ -# Copyright (C) 2010-2015 Cuckoo Foundation. -# This file is part of Cuckoo Sandbox - http://www.cuckoosandbox.org -# See the file 'docs/LICENSE' for copying permission. - -from modules.processing.parsers.CAPE.Snake import extract_config - - -def test_snake(): - with open("tests/data/malware/7b81c12fb7db9f0c317f36022ecac9faa45f5efefe24085c339c43db8b963ae2", "rb") as data: - conf = extract_config(data.read()) - assert conf == { - "Type": "Telegram", - "C2": "https://api.telegram.org/bot7952998151:AAFh98iY7kaOlHAR0qftD3ZcqGbQm0TXbBY/sendMessage?chat_id=5692813672", - } diff --git a/tests_parsers/test_sparkrat.py b/tests_parsers/test_sparkrat.py deleted file mode 100644 index 9e681b8efab..00000000000 --- a/tests_parsers/test_sparkrat.py +++ /dev/null @@ -1,36 +0,0 @@ -from contextlib import suppress - -from modules.processing.parsers.CAPE.SparkRAT import extract_config - -HAVE_MACO = False -with suppress(ImportError): - from modules.processing.parsers.MACO.SparkRAT import convert_to_MACO - - HAVE_MACO = True - - -def test_sparkrat(): - with open("tests/data/malware/ec349cfacc7658eed3640f1c475eb958c5f05bae7c2ed74d4cdb7493176daeba", "rb") as data: - conf = extract_config(data.read()) - assert conf == { - "secure": False, - "host": "67.217.62.106", - "port": 4443, - "path": "/", - "uuid": "8dc7e7d8f8576f3e55a00850b72887db", - "key": "a1348fb8969ad7a9f85ac173c2027622135e52e0e6d94d10e6a81916a29648ac", - } - if HAVE_MACO: - assert convert_to_MACO(conf).model_dump(exclude_defaults=True, exclude_none=True) == { - "family": "SparkRAT", - "identifier": ["8dc7e7d8f8576f3e55a00850b72887db"], - "other": { - "secure": False, - "host": "67.217.62.106", - "port": 4443, - "path": "/", - "uuid": "8dc7e7d8f8576f3e55a00850b72887db", - "key": "a1348fb8969ad7a9f85ac173c2027622135e52e0e6d94d10e6a81916a29648ac", - }, - "http": [{"uri": "http://67.217.62.106:4443/", "hostname": "67.217.62.106", "port": 4443, "path": "/"}], - } diff --git a/tests_parsers/test_stealc.py b/tests_parsers/test_stealc.py deleted file mode 100644 index 12a98def5df..00000000000 --- a/tests_parsers/test_stealc.py +++ /dev/null @@ -1,13 +0,0 @@ -# Copyright (C) 2010-2015 Cuckoo Foundation. -# This file is part of Cuckoo Sandbox - http://www.cuckoosandbox.org -# See the file 'docs/LICENSE' for copying permission. - -from modules.processing.parsers.CAPE.Stealc import extract_config - - -def test_stealc(): - with open("tests/data/malware/619751f5ed0a9716318092998f2e4561f27f7f429fe6103406ecf16e33837470", "rb") as data: - conf = extract_config(data.read()) - assert conf == { - "C2": ["http://95.217.125.57/2f571d994666c8cb.php"], - } diff --git a/tests_parsers/test_zloader.py b/tests_parsers/test_zloader.py deleted file mode 100644 index dda237b9ef0..00000000000 --- a/tests_parsers/test_zloader.py +++ /dev/null @@ -1,36 +0,0 @@ -# Copyright (C) 2010-2015 Cuckoo Foundation. -# This file is part of Cuckoo Sandbox - http://www.cuckoosandbox.org -# See the file 'docs/LICENSE' for copying permission. - -from contextlib import suppress - -from modules.processing.parsers.CAPE.Zloader import extract_config - -HAVE_MACO = False -with suppress(ImportError): - from modules.processing.parsers.MACO.AgentTesla import convert_to_MACO - - HAVE_MACO = True - - -def test_zloader(): - with open("tests/data/malware/adbd0c7096a7373be82dd03df1aae61cb39e0a155c00bbb9c67abc01d48718aa", "rb") as data: - conf = extract_config(data.read()) - assert conf == { - "Botnet name": "Bing_Mod5", - "Campaign ID": "M1", - "address": ["https://dem.businessdeep.com"], - "Public key": "-----BEGIN PUBLIC KEY-----MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDKGAOWVkikqE7TyKIMtWI8dFsaleTaJNXMJNIPnRE/fGCzqrV+rtY3+ex4MCHEtq2Vwppthf0Rglv8OiWgKlerIN5P6NEyCfIsFYUMDfldQTF03VES8GBIvHq5SjlIz7lawuwfdjdEkaHfOmmu9srraftkI9gZO8WRQgY1uNdsXwIDAQAB-----END PUBLIC KEY-----", - } - if HAVE_MACO: - assert convert_to_MACO(conf).model_dump(exclude_defaults=True, exclude_none=True) == { - "family": "Zloader", - "campaign_id": ["M1"], - "other": { - "Botnet name": "Bing_Mod5", - "Campaign ID": "M1", - "address": ["https://dem.businessdeep.com"], - "Public key": "-----BEGIN PUBLIC KEY-----MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDKGAOWVkikqE7TyKIMtWI8dFsaleTaJNXMJNIPnRE/fGCzqrV+rtY3+ex4MCHEtq2Vwppthf0Rglv8OiWgKlerIN5P6NEyCfIsFYUMDfldQTF03VES8GBIvHq5SjlIz7lawuwfdjdEkaHfOmmu9srraftkI9gZO8WRQgY1uNdsXwIDAQAB-----END PUBLIC KEY-----", - }, - "http": [{"uri": "https://dem.businessdeep.com"}], - } From 02a6de9069e644f961997356974bd91b4db38aa2 Mon Sep 17 00:00:00 2001 From: GitHub Actions Date: Fri, 1 Nov 2024 21:09:18 +0000 Subject: [PATCH 032/121] ci: Update requirements.txt --- requirements.txt | 1517 ++++++++++++++++++++-------------------------- 1 file changed, 660 insertions(+), 857 deletions(-) diff --git a/requirements.txt b/requirements.txt index 4b920a5528a..b6f463440e2 100644 --- a/requirements.txt +++ b/requirements.txt @@ -4,9 +4,9 @@ alembic==1.9.4 ; python_version >= "3.10" and python_version < "4.0" \ annotated-types==0.7.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53 \ --hash=sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89 -anyio==4.6.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:137b4559cbb034c477165047febb6ff83f390fc3b20bf181c1fc0a728cb8beeb \ - --hash=sha256:c7d2e9d63e31599eeb636c8c5c03a7e108d73b345f064f1c19fdc87b79036a9a +anyio==4.6.2.post1 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:4c8bc31ccdb51c7f7bd251f51c609e038d63e34219b44aa86e47576389880b4c \ + --hash=sha256:6d170c36fba3bdd840c73d3868c1e777e33676a69c3a72cf0a0d5d6d8009b61d asgiref==3.8.1 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:3e1e3ecc849832fe52ccf2cb6686b7a55f82bb1d6aee72a58826471390335e47 \ --hash=sha256:c343bd80a0bec947a9860adb4c432ffa7db769836c64238fc34bdc3fec84d590 @@ -55,6 +55,9 @@ bs4==0.0.1 ; python_version >= "3.10" and python_version < "4.0" \ cachetools==5.5.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:02134e8439cdc2ffb62023ce1debca2944c3f289d66bb17ead3ab3dede74b292 \ --hash=sha256:2cc24fb4cbe39633fb7badd9db9ca6295d766d9c2995f245725a46715d050f2a +cape-parsers==0.1.4 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:00a0541d9947257cacb6485ab513dee46812a90c22883bcc8c5eef592ff8750f \ + --hash=sha256:4957cfd4c4215c550a27ca8d3dd87a60dd834fc6b7785cf0785d35ce04211e72 capstone==4.0.2 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:0d65ffe8620920976ceadedc769f22318f6f150a592368d8a735612367ac8a1a \ --hash=sha256:2842913092c9b69fd903744bc1b87488e1451625460baac173056e1808ec1c66 \ @@ -63,9 +66,9 @@ capstone==4.0.2 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:da442f979414cf27e4621e70e835880878c858ea438c4f0e957e132593579e37 cart==1.2.2 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:c111398038683c85d3edcadaa3b16183461907bdb613e05cbb60d381f2886309 -certifi==2024.7.4 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:5a1e7645bc0ec61a09e26c36f6106dd4cf40c6db3a1fb6352b0244e7fb057c7b \ - --hash=sha256:c198e21b1289c2ab85ee4e67bb4b4ef3ead0892059901a8d5b622f24a1101e90 +certifi==2024.8.30 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:922820b53db7a7257ffbda3f597266d435245903d80737e34f8a45ff3e3230d8 \ + --hash=sha256:bec941d2aa8195e248a60b31ff9f0558284cf01a52591ceda73ea9afffd69fd9 cffi==1.17.1 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:045d61c734659cc045141be4bae381a41d89b741f795af1dd018bfb532fd0df8 \ --hash=sha256:0984a4925a435b1da406122d4d7968dd861c1385afe3b45ba82b750f229811e2 \ @@ -140,101 +143,116 @@ channels==3.0.5 ; python_version >= "3.10" and python_version < "4.0" \ chardet==4.0.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:0d6f53a15db4120f2b08c94f11e7d93d2c911ee118b6b30a04ec3ee8310179fa \ --hash=sha256:f864054d66fd9118f2e67044ac8981a54775ec5b67aed0441892edb553d21da5 -charset-normalizer==3.3.2 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:06435b539f889b1f6f4ac1758871aae42dc3a8c0e24ac9e60c2384973ad73027 \ - --hash=sha256:06a81e93cd441c56a9b65d8e1d043daeb97a3d0856d177d5c90ba85acb3db087 \ - --hash=sha256:0a55554a2fa0d408816b3b5cedf0045f4b8e1a6065aec45849de2d6f3f8e9786 \ - --hash=sha256:0b2b64d2bb6d3fb9112bafa732def486049e63de9618b5843bcdd081d8144cd8 \ - --hash=sha256:10955842570876604d404661fbccbc9c7e684caf432c09c715ec38fbae45ae09 \ - --hash=sha256:122c7fa62b130ed55f8f285bfd56d5f4b4a5b503609d181f9ad85e55c89f4185 \ - --hash=sha256:1ceae2f17a9c33cb48e3263960dc5fc8005351ee19db217e9b1bb15d28c02574 \ - --hash=sha256:1d3193f4a680c64b4b6a9115943538edb896edc190f0b222e73761716519268e \ - --hash=sha256:1f79682fbe303db92bc2b1136016a38a42e835d932bab5b3b1bfcfbf0640e519 \ - --hash=sha256:2127566c664442652f024c837091890cb1942c30937add288223dc895793f898 \ - --hash=sha256:22afcb9f253dac0696b5a4be4a1c0f8762f8239e21b99680099abd9b2b1b2269 \ - --hash=sha256:25baf083bf6f6b341f4121c2f3c548875ee6f5339300e08be3f2b2ba1721cdd3 \ - --hash=sha256:2e81c7b9c8979ce92ed306c249d46894776a909505d8f5a4ba55b14206e3222f \ - --hash=sha256:3287761bc4ee9e33561a7e058c72ac0938c4f57fe49a09eae428fd88aafe7bb6 \ - --hash=sha256:34d1c8da1e78d2e001f363791c98a272bb734000fcef47a491c1e3b0505657a8 \ - --hash=sha256:37e55c8e51c236f95b033f6fb391d7d7970ba5fe7ff453dad675e88cf303377a \ - --hash=sha256:3d47fa203a7bd9c5b6cee4736ee84ca03b8ef23193c0d1ca99b5089f72645c73 \ - --hash=sha256:3e4d1f6587322d2788836a99c69062fbb091331ec940e02d12d179c1d53e25fc \ - --hash=sha256:42cb296636fcc8b0644486d15c12376cb9fa75443e00fb25de0b8602e64c1714 \ - --hash=sha256:45485e01ff4d3630ec0d9617310448a8702f70e9c01906b0d0118bdf9d124cf2 \ - --hash=sha256:4a78b2b446bd7c934f5dcedc588903fb2f5eec172f3d29e52a9096a43722adfc \ - --hash=sha256:4ab2fe47fae9e0f9dee8c04187ce5d09f48eabe611be8259444906793ab7cbce \ - --hash=sha256:4d0d1650369165a14e14e1e47b372cfcb31d6ab44e6e33cb2d4e57265290044d \ - --hash=sha256:549a3a73da901d5bc3ce8d24e0600d1fa85524c10287f6004fbab87672bf3e1e \ - --hash=sha256:55086ee1064215781fff39a1af09518bc9255b50d6333f2e4c74ca09fac6a8f6 \ - --hash=sha256:572c3763a264ba47b3cf708a44ce965d98555f618ca42c926a9c1616d8f34269 \ - --hash=sha256:573f6eac48f4769d667c4442081b1794f52919e7edada77495aaed9236d13a96 \ - --hash=sha256:5b4c145409bef602a690e7cfad0a15a55c13320ff7a3ad7ca59c13bb8ba4d45d \ - --hash=sha256:6463effa3186ea09411d50efc7d85360b38d5f09b870c48e4600f63af490e56a \ - --hash=sha256:65f6f63034100ead094b8744b3b97965785388f308a64cf8d7c34f2f2e5be0c4 \ - --hash=sha256:663946639d296df6a2bb2aa51b60a2454ca1cb29835324c640dafb5ff2131a77 \ - --hash=sha256:6897af51655e3691ff853668779c7bad41579facacf5fd7253b0133308cf000d \ - --hash=sha256:68d1f8a9e9e37c1223b656399be5d6b448dea850bed7d0f87a8311f1ff3dabb0 \ - --hash=sha256:6ac7ffc7ad6d040517be39eb591cac5ff87416c2537df6ba3cba3bae290c0fed \ - --hash=sha256:6b3251890fff30ee142c44144871185dbe13b11bab478a88887a639655be1068 \ - --hash=sha256:6c4caeef8fa63d06bd437cd4bdcf3ffefe6738fb1b25951440d80dc7df8c03ac \ - --hash=sha256:6ef1d82a3af9d3eecdba2321dc1b3c238245d890843e040e41e470ffa64c3e25 \ - --hash=sha256:753f10e867343b4511128c6ed8c82f7bec3bd026875576dfd88483c5c73b2fd8 \ - --hash=sha256:7cd13a2e3ddeed6913a65e66e94b51d80a041145a026c27e6bb76c31a853c6ab \ - --hash=sha256:7ed9e526742851e8d5cc9e6cf41427dfc6068d4f5a3bb03659444b4cabf6bc26 \ - --hash=sha256:7f04c839ed0b6b98b1a7501a002144b76c18fb1c1850c8b98d458ac269e26ed2 \ - --hash=sha256:802fe99cca7457642125a8a88a084cef28ff0cf9407060f7b93dca5aa25480db \ - --hash=sha256:80402cd6ee291dcb72644d6eac93785fe2c8b9cb30893c1af5b8fdd753b9d40f \ - --hash=sha256:8465322196c8b4d7ab6d1e049e4c5cb460d0394da4a27d23cc242fbf0034b6b5 \ - --hash=sha256:86216b5cee4b06df986d214f664305142d9c76df9b6512be2738aa72a2048f99 \ - --hash=sha256:87d1351268731db79e0f8e745d92493ee2841c974128ef629dc518b937d9194c \ - --hash=sha256:8bdb58ff7ba23002a4c5808d608e4e6c687175724f54a5dade5fa8c67b604e4d \ - --hash=sha256:8c622a5fe39a48f78944a87d4fb8a53ee07344641b0562c540d840748571b811 \ - --hash=sha256:8d756e44e94489e49571086ef83b2bb8ce311e730092d2c34ca8f7d925cb20aa \ - --hash=sha256:8f4a014bc36d3c57402e2977dada34f9c12300af536839dc38c0beab8878f38a \ - --hash=sha256:9063e24fdb1e498ab71cb7419e24622516c4a04476b17a2dab57e8baa30d6e03 \ - --hash=sha256:90d558489962fd4918143277a773316e56c72da56ec7aa3dc3dbbe20fdfed15b \ - --hash=sha256:923c0c831b7cfcb071580d3f46c4baf50f174be571576556269530f4bbd79d04 \ - --hash=sha256:95f2a5796329323b8f0512e09dbb7a1860c46a39da62ecb2324f116fa8fdc85c \ - --hash=sha256:96b02a3dc4381e5494fad39be677abcb5e6634bf7b4fa83a6dd3112607547001 \ - --hash=sha256:9f96df6923e21816da7e0ad3fd47dd8f94b2a5ce594e00677c0013018b813458 \ - --hash=sha256:a10af20b82360ab00827f916a6058451b723b4e65030c5a18577c8b2de5b3389 \ - --hash=sha256:a50aebfa173e157099939b17f18600f72f84eed3049e743b68ad15bd69b6bf99 \ - --hash=sha256:a981a536974bbc7a512cf44ed14938cf01030a99e9b3a06dd59578882f06f985 \ - --hash=sha256:a9a8e9031d613fd2009c182b69c7b2c1ef8239a0efb1df3f7c8da66d5dd3d537 \ - --hash=sha256:ae5f4161f18c61806f411a13b0310bea87f987c7d2ecdbdaad0e94eb2e404238 \ - --hash=sha256:aed38f6e4fb3f5d6bf81bfa990a07806be9d83cf7bacef998ab1a9bd660a581f \ - --hash=sha256:b01b88d45a6fcb69667cd6d2f7a9aeb4bf53760d7fc536bf679ec94fe9f3ff3d \ - --hash=sha256:b261ccdec7821281dade748d088bb6e9b69e6d15b30652b74cbbac25e280b796 \ - --hash=sha256:b2b0a0c0517616b6869869f8c581d4eb2dd83a4d79e0ebcb7d373ef9956aeb0a \ - --hash=sha256:b4a23f61ce87adf89be746c8a8974fe1c823c891d8f86eb218bb957c924bb143 \ - --hash=sha256:bd8f7df7d12c2db9fab40bdd87a7c09b1530128315d047a086fa3ae3435cb3a8 \ - --hash=sha256:beb58fe5cdb101e3a055192ac291b7a21e3b7ef4f67fa1d74e331a7f2124341c \ - --hash=sha256:c002b4ffc0be611f0d9da932eb0f704fe2602a9a949d1f738e4c34c75b0863d5 \ - --hash=sha256:c083af607d2515612056a31f0a8d9e0fcb5876b7bfc0abad3ecd275bc4ebc2d5 \ - --hash=sha256:c180f51afb394e165eafe4ac2936a14bee3eb10debc9d9e4db8958fe36afe711 \ - --hash=sha256:c235ebd9baae02f1b77bcea61bce332cb4331dc3617d254df3323aa01ab47bd4 \ - --hash=sha256:cd70574b12bb8a4d2aaa0094515df2463cb429d8536cfb6c7ce983246983e5a6 \ - --hash=sha256:d0eccceffcb53201b5bfebb52600a5fb483a20b61da9dbc885f8b103cbe7598c \ - --hash=sha256:d965bba47ddeec8cd560687584e88cf699fd28f192ceb452d1d7ee807c5597b7 \ - --hash=sha256:db364eca23f876da6f9e16c9da0df51aa4f104a972735574842618b8c6d999d4 \ - --hash=sha256:ddbb2551d7e0102e7252db79ba445cdab71b26640817ab1e3e3648dad515003b \ - --hash=sha256:deb6be0ac38ece9ba87dea880e438f25ca3eddfac8b002a2ec3d9183a454e8ae \ - --hash=sha256:e06ed3eb3218bc64786f7db41917d4e686cc4856944f53d5bdf83a6884432e12 \ - --hash=sha256:e27ad930a842b4c5eb8ac0016b0a54f5aebbe679340c26101df33424142c143c \ - --hash=sha256:e537484df0d8f426ce2afb2d0f8e1c3d0b114b83f8850e5f2fbea0e797bd82ae \ - --hash=sha256:eb00ed941194665c332bf8e078baf037d6c35d7c4f3102ea2d4f16ca94a26dc8 \ - --hash=sha256:eb6904c354526e758fda7167b33005998fb68c46fbc10e013ca97f21ca5c8887 \ - --hash=sha256:eb8821e09e916165e160797a6c17edda0679379a4be5c716c260e836e122f54b \ - --hash=sha256:efcb3f6676480691518c177e3b465bcddf57cea040302f9f4e6e191af91174d4 \ - --hash=sha256:f27273b60488abe721a075bcca6d7f3964f9f6f067c8c4c605743023d7d3944f \ - --hash=sha256:f30c3cb33b24454a82faecaf01b19c18562b1e89558fb6c56de4d9118a032fd5 \ - --hash=sha256:fb69256e180cb6c8a894fee62b3afebae785babc1ee98b81cdf68bbca1987f33 \ - --hash=sha256:fd1abc0d89e30cc4e02e4064dc67fcc51bd941eb395c502aac3ec19fab46b519 \ - --hash=sha256:ff8fa367d09b717b2a17a052544193ad76cd49979c805768879cb63d9ca50561 +charset-normalizer==3.4.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:0099d79bdfcf5c1f0c2c72f91516702ebf8b0b8ddd8905f97a8aecf49712c621 \ + --hash=sha256:0713f3adb9d03d49d365b70b84775d0a0d18e4ab08d12bc46baa6132ba78aaf6 \ + --hash=sha256:07afec21bbbbf8a5cc3651aa96b980afe2526e7f048fdfb7f1014d84acc8b6d8 \ + --hash=sha256:0b309d1747110feb25d7ed6b01afdec269c647d382c857ef4663bbe6ad95a912 \ + --hash=sha256:0d99dd8ff461990f12d6e42c7347fd9ab2532fb70e9621ba520f9e8637161d7c \ + --hash=sha256:0de7b687289d3c1b3e8660d0741874abe7888100efe14bd0f9fd7141bcbda92b \ + --hash=sha256:1110e22af8ca26b90bd6364fe4c763329b0ebf1ee213ba32b68c73de5752323d \ + --hash=sha256:130272c698667a982a5d0e626851ceff662565379baf0ff2cc58067b81d4f11d \ + --hash=sha256:136815f06a3ae311fae551c3df1f998a1ebd01ddd424aa5603a4336997629e95 \ + --hash=sha256:14215b71a762336254351b00ec720a8e85cada43b987da5a042e4ce3e82bd68e \ + --hash=sha256:1db4e7fefefd0f548d73e2e2e041f9df5c59e178b4c72fbac4cc6f535cfb1565 \ + --hash=sha256:1ffd9493de4c922f2a38c2bf62b831dcec90ac673ed1ca182fe11b4d8e9f2a64 \ + --hash=sha256:2006769bd1640bdf4d5641c69a3d63b71b81445473cac5ded39740a226fa88ab \ + --hash=sha256:20587d20f557fe189b7947d8e7ec5afa110ccf72a3128d61a2a387c3313f46be \ + --hash=sha256:223217c3d4f82c3ac5e29032b3f1c2eb0fb591b72161f86d93f5719079dae93e \ + --hash=sha256:27623ba66c183eca01bf9ff833875b459cad267aeeb044477fedac35e19ba907 \ + --hash=sha256:285e96d9d53422efc0d7a17c60e59f37fbf3dfa942073f666db4ac71e8d726d0 \ + --hash=sha256:2de62e8801ddfff069cd5c504ce3bc9672b23266597d4e4f50eda28846c322f2 \ + --hash=sha256:2f6c34da58ea9c1a9515621f4d9ac379871a8f21168ba1b5e09d74250de5ad62 \ + --hash=sha256:309a7de0a0ff3040acaebb35ec45d18db4b28232f21998851cfa709eeff49d62 \ + --hash=sha256:35c404d74c2926d0287fbd63ed5d27eb911eb9e4a3bb2c6d294f3cfd4a9e0c23 \ + --hash=sha256:3710a9751938947e6327ea9f3ea6332a09bf0ba0c09cae9cb1f250bd1f1549bc \ + --hash=sha256:3d59d125ffbd6d552765510e3f31ed75ebac2c7470c7274195b9161a32350284 \ + --hash=sha256:40d3ff7fc90b98c637bda91c89d51264a3dcf210cade3a2c6f838c7268d7a4ca \ + --hash=sha256:425c5f215d0eecee9a56cdb703203dda90423247421bf0d67125add85d0c4455 \ + --hash=sha256:43193c5cda5d612f247172016c4bb71251c784d7a4d9314677186a838ad34858 \ + --hash=sha256:44aeb140295a2f0659e113b31cfe92c9061622cadbc9e2a2f7b8ef6b1e29ef4b \ + --hash=sha256:47334db71978b23ebcf3c0f9f5ee98b8d65992b65c9c4f2d34c2eaf5bcaf0594 \ + --hash=sha256:4796efc4faf6b53a18e3d46343535caed491776a22af773f366534056c4e1fbc \ + --hash=sha256:4a51b48f42d9358460b78725283f04bddaf44a9358197b889657deba38f329db \ + --hash=sha256:4b67fdab07fdd3c10bb21edab3cbfe8cf5696f453afce75d815d9d7223fbe88b \ + --hash=sha256:4ec9dd88a5b71abfc74e9df5ebe7921c35cbb3b641181a531ca65cdb5e8e4dea \ + --hash=sha256:4f9fc98dad6c2eaa32fc3af1417d95b5e3d08aff968df0cd320066def971f9a6 \ + --hash=sha256:54b6a92d009cbe2fb11054ba694bc9e284dad30a26757b1e372a1fdddaf21920 \ + --hash=sha256:55f56e2ebd4e3bc50442fbc0888c9d8c94e4e06a933804e2af3e89e2f9c1c749 \ + --hash=sha256:5726cf76c982532c1863fb64d8c6dd0e4c90b6ece9feb06c9f202417a31f7dd7 \ + --hash=sha256:5d447056e2ca60382d460a604b6302d8db69476fd2015c81e7c35417cfabe4cd \ + --hash=sha256:5ed2e36c3e9b4f21dd9422f6893dec0abf2cca553af509b10cd630f878d3eb99 \ + --hash=sha256:5ff2ed8194587faf56555927b3aa10e6fb69d931e33953943bc4f837dfee2242 \ + --hash=sha256:62f60aebecfc7f4b82e3f639a7d1433a20ec32824db2199a11ad4f5e146ef5ee \ + --hash=sha256:63bc5c4ae26e4bc6be6469943b8253c0fd4e4186c43ad46e713ea61a0ba49129 \ + --hash=sha256:6b40e8d38afe634559e398cc32b1472f376a4099c75fe6299ae607e404c033b2 \ + --hash=sha256:6b493a043635eb376e50eedf7818f2f322eabbaa974e948bd8bdd29eb7ef2a51 \ + --hash=sha256:6dba5d19c4dfab08e58d5b36304b3f92f3bd5d42c1a3fa37b5ba5cdf6dfcbcee \ + --hash=sha256:6fd30dc99682dc2c603c2b315bded2799019cea829f8bf57dc6b61efde6611c8 \ + --hash=sha256:707b82d19e65c9bd28b81dde95249b07bf9f5b90ebe1ef17d9b57473f8a64b7b \ + --hash=sha256:7706f5850360ac01d80c89bcef1640683cc12ed87f42579dab6c5d3ed6888613 \ + --hash=sha256:7782afc9b6b42200f7362858f9e73b1f8316afb276d316336c0ec3bd73312742 \ + --hash=sha256:79983512b108e4a164b9c8d34de3992f76d48cadc9554c9e60b43f308988aabe \ + --hash=sha256:7f683ddc7eedd742e2889d2bfb96d69573fde1d92fcb811979cdb7165bb9c7d3 \ + --hash=sha256:82357d85de703176b5587dbe6ade8ff67f9f69a41c0733cf2425378b49954de5 \ + --hash=sha256:84450ba661fb96e9fd67629b93d2941c871ca86fc38d835d19d4225ff946a631 \ + --hash=sha256:86f4e8cca779080f66ff4f191a685ced73d2f72d50216f7112185dc02b90b9b7 \ + --hash=sha256:8cda06946eac330cbe6598f77bb54e690b4ca93f593dee1568ad22b04f347c15 \ + --hash=sha256:8ce7fd6767a1cc5a92a639b391891bf1c268b03ec7e021c7d6d902285259685c \ + --hash=sha256:8ff4e7cdfdb1ab5698e675ca622e72d58a6fa2a8aa58195de0c0061288e6e3ea \ + --hash=sha256:9289fd5dddcf57bab41d044f1756550f9e7cf0c8e373b8cdf0ce8773dc4bd417 \ + --hash=sha256:92a7e36b000bf022ef3dbb9c46bfe2d52c047d5e3f3343f43204263c5addc250 \ + --hash=sha256:92db3c28b5b2a273346bebb24857fda45601aef6ae1c011c0a997106581e8a88 \ + --hash=sha256:95c3c157765b031331dd4db3c775e58deaee050a3042fcad72cbc4189d7c8dca \ + --hash=sha256:980b4f289d1d90ca5efcf07958d3eb38ed9c0b7676bf2831a54d4f66f9c27dfa \ + --hash=sha256:9ae4ef0b3f6b41bad6366fb0ea4fc1d7ed051528e113a60fa2a65a9abb5b1d99 \ + --hash=sha256:9c98230f5042f4945f957d006edccc2af1e03ed5e37ce7c373f00a5a4daa6149 \ + --hash=sha256:9fa2566ca27d67c86569e8c85297aaf413ffab85a8960500f12ea34ff98e4c41 \ + --hash=sha256:a14969b8691f7998e74663b77b4c36c0337cb1df552da83d5c9004a93afdb574 \ + --hash=sha256:a8aacce6e2e1edcb6ac625fb0f8c3a9570ccc7bfba1f63419b3769ccf6a00ed0 \ + --hash=sha256:a8e538f46104c815be19c975572d74afb53f29650ea2025bbfaef359d2de2f7f \ + --hash=sha256:aa41e526a5d4a9dfcfbab0716c7e8a1b215abd3f3df5a45cf18a12721d31cb5d \ + --hash=sha256:aa693779a8b50cd97570e5a0f343538a8dbd3e496fa5dcb87e29406ad0299654 \ + --hash=sha256:ab22fbd9765e6954bc0bcff24c25ff71dcbfdb185fcdaca49e81bac68fe724d3 \ + --hash=sha256:ab2e5bef076f5a235c3774b4f4028a680432cded7cad37bba0fd90d64b187d19 \ + --hash=sha256:ab973df98fc99ab39080bfb0eb3a925181454d7c3ac8a1e695fddfae696d9e90 \ + --hash=sha256:af73657b7a68211996527dbfeffbb0864e043d270580c5aef06dc4b659a4b578 \ + --hash=sha256:b197e7094f232959f8f20541ead1d9862ac5ebea1d58e9849c1bf979255dfac9 \ + --hash=sha256:b295729485b06c1a0683af02a9e42d2caa9db04a373dc38a6a58cdd1e8abddf1 \ + --hash=sha256:b8831399554b92b72af5932cdbbd4ddc55c55f631bb13ff8fe4e6536a06c5c51 \ + --hash=sha256:b8dcd239c743aa2f9c22ce674a145e0a25cb1566c495928440a181ca1ccf6719 \ + --hash=sha256:bcb4f8ea87d03bc51ad04add8ceaf9b0f085ac045ab4d74e73bbc2dc033f0236 \ + --hash=sha256:bd7af3717683bea4c87acd8c0d3d5b44d56120b26fd3f8a692bdd2d5260c620a \ + --hash=sha256:bf4475b82be41b07cc5e5ff94810e6a01f276e37c2d55571e3fe175e467a1a1c \ + --hash=sha256:c3e446d253bd88f6377260d07c895816ebf33ffffd56c1c792b13bff9c3e1ade \ + --hash=sha256:c57516e58fd17d03ebe67e181a4e4e2ccab1168f8c2976c6a334d4f819fe5944 \ + --hash=sha256:c94057af19bc953643a33581844649a7fdab902624d2eb739738a30e2b3e60fc \ + --hash=sha256:cab5d0b79d987c67f3b9e9c53f54a61360422a5a0bc075f43cab5621d530c3b6 \ + --hash=sha256:ce031db0408e487fd2775d745ce30a7cd2923667cf3b69d48d219f1d8f5ddeb6 \ + --hash=sha256:cee4373f4d3ad28f1ab6290684d8e2ebdb9e7a1b74fdc39e4c211995f77bec27 \ + --hash=sha256:d5b054862739d276e09928de37c79ddeec42a6e1bfc55863be96a36ba22926f6 \ + --hash=sha256:dbe03226baf438ac4fda9e2d0715022fd579cb641c4cf639fa40d53b2fe6f3e2 \ + --hash=sha256:dc15e99b2d8a656f8e666854404f1ba54765871104e50c8e9813af8a7db07f12 \ + --hash=sha256:dcaf7c1524c0542ee2fc82cc8ec337f7a9f7edee2532421ab200d2b920fc97cf \ + --hash=sha256:dd4eda173a9fcccb5f2e2bd2a9f423d180194b1bf17cf59e3269899235b2a114 \ + --hash=sha256:dd9a8bd8900e65504a305bf8ae6fa9fbc66de94178c420791d0293702fce2df7 \ + --hash=sha256:de7376c29d95d6719048c194a9cf1a1b0393fbe8488a22008610b0361d834ecf \ + --hash=sha256:e7fdd52961feb4c96507aa649550ec2a0d527c086d284749b2f582f2d40a2e0d \ + --hash=sha256:e91f541a85298cf35433bf66f3fab2a4a2cff05c127eeca4af174f6d497f0d4b \ + --hash=sha256:e9e3c4c9e1ed40ea53acf11e2a386383c3304212c965773704e4603d589343ed \ + --hash=sha256:ee803480535c44e7f5ad00788526da7d85525cfefaf8acf8ab9a310000be4b03 \ + --hash=sha256:f09cb5a7bbe1ecae6e87901a2eb23e0256bb524a79ccc53eb0b7629fbe7677c4 \ + --hash=sha256:f19c1585933c82098c2a520f8ec1227f20e339e33aca8fa6f956f6691b784e67 \ + --hash=sha256:f1a2f519ae173b5b6a2c9d5fa3116ce16e48b3462c8b96dfdded11055e3d6365 \ + --hash=sha256:f28f891ccd15c514a0981f3b9db9aa23d62fe1a99997512b0491d2ed323d229a \ + --hash=sha256:f3e73a4255342d4eb26ef6df01e3962e73aa29baa3124a8e824c5d3364a65748 \ + --hash=sha256:f606a1881d2663630ea5b8ce2efe2111740df4b687bd78b34a8131baa007f79b \ + --hash=sha256:fe9f97feb71aa9896b81973a7bbada8c49501dc73e58a10fcef6663af95e5079 \ + --hash=sha256:ffc519621dce0c767e96b9c53f09c5d215578e10b02c285809f76509a3931482 click==8.1.7 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28 \ --hash=sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de -colorama==0.4.6 ; python_version >= "3.10" and python_version < "4.0" \ +colorama==0.4.6 ; python_version >= "3.10" and python_version < "4.0" and (sys_platform == "win32" or platform_system == "Windows") \ --hash=sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44 \ --hash=sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6 colorclass==2.2.2 ; python_version >= "3.10" and python_version < "4.0" \ @@ -274,9 +292,6 @@ cryptography==43.0.1 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:ea25acb556320250756e53f9e20a4177515f012c9eaea17eb7587a8c4d8ae034 \ --hash=sha256:f98bf604c82c416bc829e490c700ca1553eafdf2912a91e23a79d97d9801372a \ --hash=sha256:fba1007b3ef89946dbbb515aeeb41e30203b004f0b4b00e5e16078b518563289 -cxxfilt==0.3.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:774e85a8d0157775ed43276d89397d924b104135762d86b3a95f81f203094e07 \ - --hash=sha256:7df6464ba5e8efbf0d8974c0b2c78b32546676f06059a83515dbdfa559b34214 cython==0.29.24 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:09ac3087ac7a3d489ebcb3fb8402e00c13d1a3a1c6bc73fd3b0d756a3e341e79 \ --hash=sha256:0a142c6b862e6ed6b02209d543062c038c110585b5e32d1ad7c9717af4f07e41 \ @@ -367,9 +382,9 @@ djangorestframework==3.15.2 ; python_version >= "3.10" and python_version < "4.0 dncil==1.0.2 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:1557675c2d1351d3260509881cff0383309f81cda4944ed2c3f5cc352953aa15 \ --hash=sha256:69d389e9b850fa9afa2e37ca252b01476379991eee88fd33ab76f924d36dd68d -dnfile==0.15.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:d60239de76035bed22f3c131925cf8d484f44a9da03c19659a01a615309add55 \ - --hash=sha256:e4ae8803a59d8f845c11524e8b007104b43c90adc2fb0a81dcdc2972c47dfc80 +dnfile==0.15.1 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:1529cf0f976b1382f60a3c56b2e0def90f3486e41193ffd34677e74563c8426c \ + --hash=sha256:585c8e3e4a29824402430a0a8b7e7ae82c040fc17eeb3a06758fdceebe2d923e dnspython==2.6.1 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:5ef3b9680161f6fa89daf8ad451b5f1a33b18ae8a1c6778cdf4b43f08c0a6e50 \ --hash=sha256:e8f0f9c23a7b7cb99ded64e6c3a6f3e701d78f50c55e002b839dea7225cff7cc @@ -385,12 +400,6 @@ exceptiongroup==1.2.2 ; python_version >= "3.10" and python_version < "3.11" \ filelock==3.16.1 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:2082e5703d51fbf98ea75855d9d5527e33d8ff23099bec374a134febee6946b0 \ --hash=sha256:c249fbfcd5db47e5e2d6d62198e565475ee65e4831e2561c8e313fa7eb961435 -flare-capa==7.3.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:21be4c9ce0af093bb0590ec7fd807096483d16c68753a375576420fe8ebcfecf \ - --hash=sha256:f7a7f35f4dce1aca723fcc792a6afbc384a696d889ef891649dc823d948e43ff -funcy==2.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:3963315d59d41c6f30c04bc910e10ab50a3ac4a225868bfa96feed133df075cb \ - --hash=sha256:53df23c8bb1651b12f095df764bfb057935d49537a56de211b098f4c79614bb0 future==1.0.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:929292d34f5872e70396626ef385ec22355a1fae8ad29e1a734c3e43f9fbc216 \ --hash=sha256:bd2968309307861edae1458a4f8a4f3598c03be43b97521076aebf5d94c07b05 @@ -501,55 +510,53 @@ gunicorn==22.0.0 ; python_version >= "3.10" and python_version < "4.0" \ h11==0.14.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d \ --hash=sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761 -httptools==0.6.1 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:00d5d4b68a717765b1fabfd9ca755bd12bf44105eeb806c03d1962acd9b8e563 \ - --hash=sha256:0ac5a0ae3d9f4fe004318d64b8a854edd85ab76cffbf7ef5e32920faef62f142 \ - --hash=sha256:0cf2372e98406efb42e93bfe10f2948e467edfd792b015f1b4ecd897903d3e8d \ - --hash=sha256:1ed99a373e327f0107cb513b61820102ee4f3675656a37a50083eda05dc9541b \ - --hash=sha256:3c3b214ce057c54675b00108ac42bacf2ab8f85c58e3f324a4e963bbc46424f4 \ - --hash=sha256:3e802e0b2378ade99cd666b5bffb8b2a7cc8f3d28988685dc300469ea8dd86cb \ - --hash=sha256:3f30d3ce413088a98b9db71c60a6ada2001a08945cb42dd65a9a9fe228627658 \ - --hash=sha256:405784577ba6540fa7d6ff49e37daf104e04f4b4ff2d1ac0469eaa6a20fde084 \ - --hash=sha256:48ed8129cd9a0d62cf4d1575fcf90fb37e3ff7d5654d3a5814eb3d55f36478c2 \ - --hash=sha256:4bd3e488b447046e386a30f07af05f9b38d3d368d1f7b4d8f7e10af85393db97 \ - --hash=sha256:4f0f8271c0a4db459f9dc807acd0eadd4839934a4b9b892f6f160e94da309837 \ - --hash=sha256:5cceac09f164bcba55c0500a18fe3c47df29b62353198e4f37bbcc5d591172c3 \ - --hash=sha256:639dc4f381a870c9ec860ce5c45921db50205a37cc3334e756269736ff0aac58 \ - --hash=sha256:678fcbae74477a17d103b7cae78b74800d795d702083867ce160fc202104d0da \ - --hash=sha256:6a4f5ccead6d18ec072ac0b84420e95d27c1cdf5c9f1bc8fbd8daf86bd94f43d \ - --hash=sha256:6f58e335a1402fb5a650e271e8c2d03cfa7cea46ae124649346d17bd30d59c90 \ - --hash=sha256:75c8022dca7935cba14741a42744eee13ba05db00b27a4b940f0d646bd4d56d0 \ - --hash=sha256:7a7ea483c1a4485c71cb5f38be9db078f8b0e8b4c4dc0210f531cdd2ddac1ef1 \ - --hash=sha256:7d9ceb2c957320def533671fc9c715a80c47025139c8d1f3797477decbc6edd2 \ - --hash=sha256:7ebaec1bf683e4bf5e9fbb49b8cc36da482033596a415b3e4ebab5a4c0d7ec5e \ - --hash=sha256:85ed077c995e942b6f1b07583e4eb0a8d324d418954fc6af913d36db7c05a5a0 \ - --hash=sha256:8ae5b97f690badd2ca27cbf668494ee1b6d34cf1c464271ef7bfa9ca6b83ffaf \ - --hash=sha256:8b0bb634338334385351a1600a73e558ce619af390c2b38386206ac6a27fecfc \ - --hash=sha256:8e216a038d2d52ea13fdd9b9c9c7459fb80d78302b257828285eca1c773b99b3 \ - --hash=sha256:93ad80d7176aa5788902f207a4e79885f0576134695dfb0fefc15b7a4648d503 \ - --hash=sha256:95658c342529bba4e1d3d2b1a874db16c7cca435e8827422154c9da76ac4e13a \ - --hash=sha256:95fb92dd3649f9cb139e9c56604cc2d7c7bf0fc2e7c8d7fbd58f96e35eddd2a3 \ - --hash=sha256:97662ce7fb196c785344d00d638fc9ad69e18ee4bfb4000b35a52efe5adcc949 \ - --hash=sha256:9bb68d3a085c2174c2477eb3ffe84ae9fb4fde8792edb7bcd09a1d8467e30a84 \ - --hash=sha256:b512aa728bc02354e5ac086ce76c3ce635b62f5fbc32ab7082b5e582d27867bb \ - --hash=sha256:c6e26c30455600b95d94b1b836085138e82f177351454ee841c148f93a9bad5a \ - --hash=sha256:d2f6c3c4cb1948d912538217838f6e9960bc4a521d7f9b323b3da579cd14532f \ - --hash=sha256:dcbab042cc3ef272adc11220517278519adf8f53fd3056d0e68f0a6f891ba94e \ - --hash=sha256:e0b281cf5a125c35f7f6722b65d8542d2e57331be573e9e88bc8b0115c4a7a81 \ - --hash=sha256:e57997ac7fb7ee43140cc03664de5f268813a481dff6245e0075925adc6aa185 \ - --hash=sha256:fe467eb086d80217b7584e61313ebadc8d187a4d95bb62031b7bab4b205c3ba3 -humanize==4.10.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:06b6eb0293e4b85e8d385397c5868926820db32b9b654b932f57fa41c23c9978 \ - --hash=sha256:39e7ccb96923e732b5c2e27aeaa3b10a8dfeeba3eb965ba7b74a3eb0e30040a6 +httptools==0.6.4 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:0614154d5454c21b6410fdf5262b4a3ddb0f53f1e1721cfd59d55f32138c578a \ + --hash=sha256:0e563e54979e97b6d13f1bbc05a96109923e76b901f786a5eae36e99c01237bd \ + --hash=sha256:16e603a3bff50db08cd578d54f07032ca1631450ceb972c2f834c2b860c28ea2 \ + --hash=sha256:288cd628406cc53f9a541cfaf06041b4c71d751856bab45e3702191f931ccd17 \ + --hash=sha256:28908df1b9bb8187393d5b5db91435ccc9c8e891657f9cbb42a2541b44c82fc8 \ + --hash=sha256:322d20ea9cdd1fa98bd6a74b77e2ec5b818abdc3d36695ab402a0de8ef2865a3 \ + --hash=sha256:342dd6946aa6bda4b8f18c734576106b8a31f2fe31492881a9a160ec84ff4bd5 \ + --hash=sha256:345c288418f0944a6fe67be8e6afa9262b18c7626c3ef3c28adc5eabc06a68da \ + --hash=sha256:3c73ce323711a6ffb0d247dcd5a550b8babf0f757e86a52558fe5b86d6fefcc0 \ + --hash=sha256:40a5ec98d3f49904b9fe36827dcf1aadfef3b89e2bd05b0e35e94f97c2b14721 \ + --hash=sha256:40b0f7fe4fd38e6a507bdb751db0379df1e99120c65fbdc8ee6c1d044897a636 \ + --hash=sha256:40dc6a8e399e15ea525305a2ddba998b0af5caa2566bcd79dcbe8948181eeaff \ + --hash=sha256:4b36913ba52008249223042dca46e69967985fb4051951f94357ea681e1f5dc0 \ + --hash=sha256:4d87b29bd4486c0093fc64dea80231f7c7f7eb4dc70ae394d70a495ab8436071 \ + --hash=sha256:4e93eee4add6493b59a5c514da98c939b244fce4a0d8879cd3f466562f4b7d5c \ + --hash=sha256:59e724f8b332319e2875efd360e61ac07f33b492889284a3e05e6d13746876f4 \ + --hash=sha256:69422b7f458c5af875922cdb5bd586cc1f1033295aa9ff63ee196a87519ac8e1 \ + --hash=sha256:703c346571fa50d2e9856a37d7cd9435a25e7fd15e236c397bf224afaa355fe9 \ + --hash=sha256:85071a1e8c2d051b507161f6c3e26155b5c790e4e28d7f236422dbacc2a9cc44 \ + --hash=sha256:856f4bc0478ae143bad54a4242fccb1f3f86a6e1be5548fecfd4102061b3a083 \ + --hash=sha256:85797e37e8eeaa5439d33e556662cc370e474445d5fab24dcadc65a8ffb04003 \ + --hash=sha256:90d96a385fa941283ebd231464045187a31ad932ebfa541be8edf5b3c2328959 \ + --hash=sha256:94978a49b8f4569ad607cd4946b759d90b285e39c0d4640c6b36ca7a3ddf2efc \ + --hash=sha256:aafe0f1918ed07b67c1e838f950b1c1fabc683030477e60b335649b8020e1076 \ + --hash=sha256:ab9ba8dcf59de5181f6be44a77458e45a578fc99c31510b8c65b7d5acc3cf490 \ + --hash=sha256:ade273d7e767d5fae13fa637f4d53b6e961fb7fd93c7797562663f0171c26660 \ + --hash=sha256:b799de31416ecc589ad79dd85a0b2657a8fe39327944998dea368c1d4c9e55e6 \ + --hash=sha256:c26f313951f6e26147833fc923f78f95604bbec812a43e5ee37f26dc9e5a686c \ + --hash=sha256:ca80b7485c76f768a3bc83ea58373f8db7b015551117375e4918e2aa77ea9b50 \ + --hash=sha256:d1ffd262a73d7c28424252381a5b854c19d9de5f56f075445d33919a637e3547 \ + --hash=sha256:d3f0d369e7ffbe59c4b6116a44d6a8eb4783aae027f2c0b366cf0aa964185dba \ + --hash=sha256:d54efd20338ac52ba31e7da78e4a72570cf729fac82bc31ff9199bedf1dc7440 \ + --hash=sha256:dacdd3d10ea1b4ca9df97a0a303cbacafc04b5cd375fa98732678151643d4988 \ + --hash=sha256:db353d22843cf1028f43c3651581e4bb49374d85692a85f95f7b9a130e1b2cab \ + --hash=sha256:db78cb9ca56b59b016e64b6031eda5653be0589dba2b1b43453f6e8b405a0970 \ + --hash=sha256:deee0e3343f98ee8047e9f4c5bc7cedbf69f5734454a94c38ee829fb2d5fa3c1 \ + --hash=sha256:df017d6c780287d5c80601dafa31f17bddb170232d85c066604d8558683711a2 \ + --hash=sha256:df959752a0c2748a65ab5387d08287abf6779ae9165916fe053e68ae1fbdc47f \ + --hash=sha256:ec4f178901fa1834d4a060320d2f3abc5c9e39766953d038f1458cb885f47e81 \ + --hash=sha256:f47f8ed67cc0ff862b84a1189831d1d33c963fb3ce1ee0c65d3b0cbe7b711069 \ + --hash=sha256:f8787367fbdfccae38e35abf7641dafc5310310a5987b689f4c32cc8cc3ee975 \ + --hash=sha256:f9eb89ecf8b290f2e293325c646a211ff1c2493222798bb80a530c5e7502494f \ + --hash=sha256:fc411e1c0a7dcd2f902c7c48cf079947a7e65b5485dea9decb82b9105ca71a43 hyperlink==21.0.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:427af957daa58bc909471c6c40f74c5450fa123dd093fc53efd2e91d2705a56b \ --hash=sha256:e6b14c37ecb73e89c77d78cdb4c2cc8f3fb59a885c5b3f819ff4ed80f25af1b4 -ida-netnode==3.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:b7e1f2fbf57e3e104ed779d58e5f3f050aa48cce581bab8bf14ccee7a315e32e \ - --hash=sha256:b9d117703e076c9d219c9337d0b43d935b5102b5cb677835f7c9776a9f0340a5 -ida-settings==2.1.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:1371730b4e64bf388845b65a41bea094ebde8a5d3a05bdf4edf2f42aaba83262 \ - --hash=sha256:eab913b31ed0565aacea6d31976696c33b60c7e7bce3fccb75f32bef3878fc61 idna==3.10 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9 \ --hash=sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3 @@ -560,8 +567,6 @@ iniparse==0.5 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:88ca60473b1637055a937933d48840be1b1b6835f381a6158ef118a532583675 \ --hash=sha256:932e5239d526e7acb504017bb707be67019ac428a6932368e6851691093aa842 \ --hash=sha256:db6ef1d8a02395448e0e7b17ac0aa28b8d338b632bbd1ffca08c02ddae32cf97 -intervaltree==3.1.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:902b1b88936918f9b2a19e0e5eb7ccb430ae45cde4f39ea4b36932920d33952d jinja2==3.1.4 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:4a3aee7acbbe7303aede8e9648d13b8bf88a429282aa6122a993f0ac800cb369 \ --hash=sha256:bc5dd2abb727a5319567b7a813e6a2e7318c39f4f487cfe6c89c6f9c7d25197d @@ -571,73 +576,71 @@ lnkparse3==1.2.0 ; python_version >= "3.10" and python_version < "4.0" \ maco==1.1.8 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:ab2d1d8e846c0abc455d16f718ba71dda5492ddc22533484156090aa4439fb06 \ --hash=sha256:e0985efdf645d3c55e3d4d4f2bf40b8d2260fa4add608bb8e8fdefba0500cb4a -mako==1.3.5 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:260f1dbc3a519453a9c856dedfe4beb4e50bd5a26d96386cb6c80856556bb91a \ - --hash=sha256:48dbc20568c1d276a2698b36d968fa76161bf127194907ea6fc594fa81f943bc -markdown-it-py==3.0.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1 \ - --hash=sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb -markupsafe==2.1.5 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:00e046b6dd71aa03a41079792f8473dc494d564611a8f89bbbd7cb93295ebdcf \ - --hash=sha256:075202fa5b72c86ad32dc7d0b56024ebdbcf2048c0ba09f1cde31bfdd57bcfff \ - --hash=sha256:0e397ac966fdf721b2c528cf028494e86172b4feba51d65f81ffd65c63798f3f \ - --hash=sha256:17b950fccb810b3293638215058e432159d2b71005c74371d784862b7e4683f3 \ - --hash=sha256:1f3fbcb7ef1f16e48246f704ab79d79da8a46891e2da03f8783a5b6fa41a9532 \ - --hash=sha256:2174c595a0d73a3080ca3257b40096db99799265e1c27cc5a610743acd86d62f \ - --hash=sha256:2b7c57a4dfc4f16f7142221afe5ba4e093e09e728ca65c51f5620c9aaeb9a617 \ - --hash=sha256:2d2d793e36e230fd32babe143b04cec8a8b3eb8a3122d2aceb4a371e6b09b8df \ - --hash=sha256:30b600cf0a7ac9234b2638fbc0fb6158ba5bdcdf46aeb631ead21248b9affbc4 \ - --hash=sha256:397081c1a0bfb5124355710fe79478cdbeb39626492b15d399526ae53422b906 \ - --hash=sha256:3a57fdd7ce31c7ff06cdfbf31dafa96cc533c21e443d57f5b1ecc6cdc668ec7f \ - --hash=sha256:3c6b973f22eb18a789b1460b4b91bf04ae3f0c4234a0a6aa6b0a92f6f7b951d4 \ - --hash=sha256:3e53af139f8579a6d5f7b76549125f0d94d7e630761a2111bc431fd820e163b8 \ - --hash=sha256:4096e9de5c6fdf43fb4f04c26fb114f61ef0bf2e5604b6ee3019d51b69e8c371 \ - --hash=sha256:4275d846e41ecefa46e2015117a9f491e57a71ddd59bbead77e904dc02b1bed2 \ - --hash=sha256:4c31f53cdae6ecfa91a77820e8b151dba54ab528ba65dfd235c80b086d68a465 \ - --hash=sha256:4f11aa001c540f62c6166c7726f71f7573b52c68c31f014c25cc7901deea0b52 \ - --hash=sha256:5049256f536511ee3f7e1b3f87d1d1209d327e818e6ae1365e8653d7e3abb6a6 \ - --hash=sha256:58c98fee265677f63a4385256a6d7683ab1832f3ddd1e66fe948d5880c21a169 \ - --hash=sha256:598e3276b64aff0e7b3451b72e94fa3c238d452e7ddcd893c3ab324717456bad \ - --hash=sha256:5b7b716f97b52c5a14bffdf688f971b2d5ef4029127f1ad7a513973cfd818df2 \ - --hash=sha256:5dedb4db619ba5a2787a94d877bc8ffc0566f92a01c0ef214865e54ecc9ee5e0 \ - --hash=sha256:619bc166c4f2de5caa5a633b8b7326fbe98e0ccbfacabd87268a2b15ff73a029 \ - --hash=sha256:629ddd2ca402ae6dbedfceeba9c46d5f7b2a61d9749597d4307f943ef198fc1f \ - --hash=sha256:656f7526c69fac7f600bd1f400991cc282b417d17539a1b228617081106feb4a \ - --hash=sha256:6ec585f69cec0aa07d945b20805be741395e28ac1627333b1c5b0105962ffced \ - --hash=sha256:72b6be590cc35924b02c78ef34b467da4ba07e4e0f0454a2c5907f473fc50ce5 \ - --hash=sha256:7502934a33b54030eaf1194c21c692a534196063db72176b0c4028e140f8f32c \ - --hash=sha256:7a68b554d356a91cce1236aa7682dc01df0edba8d043fd1ce607c49dd3c1edcf \ - --hash=sha256:7b2e5a267c855eea6b4283940daa6e88a285f5f2a67f2220203786dfa59b37e9 \ - --hash=sha256:823b65d8706e32ad2df51ed89496147a42a2a6e01c13cfb6ffb8b1e92bc910bb \ - --hash=sha256:8590b4ae07a35970728874632fed7bd57b26b0102df2d2b233b6d9d82f6c62ad \ - --hash=sha256:8dd717634f5a044f860435c1d8c16a270ddf0ef8588d4887037c5028b859b0c3 \ - --hash=sha256:8dec4936e9c3100156f8a2dc89c4b88d5c435175ff03413b443469c7c8c5f4d1 \ - --hash=sha256:97cafb1f3cbcd3fd2b6fbfb99ae11cdb14deea0736fc2b0952ee177f2b813a46 \ - --hash=sha256:a17a92de5231666cfbe003f0e4b9b3a7ae3afb1ec2845aadc2bacc93ff85febc \ - --hash=sha256:a549b9c31bec33820e885335b451286e2969a2d9e24879f83fe904a5ce59d70a \ - --hash=sha256:ac07bad82163452a6884fe8fa0963fb98c2346ba78d779ec06bd7a6262132aee \ - --hash=sha256:ae2ad8ae6ebee9d2d94b17fb62763125f3f374c25618198f40cbb8b525411900 \ - --hash=sha256:b91c037585eba9095565a3556f611e3cbfaa42ca1e865f7b8015fe5c7336d5a5 \ - --hash=sha256:bc1667f8b83f48511b94671e0e441401371dfd0f0a795c7daa4a3cd1dde55bea \ - --hash=sha256:bec0a414d016ac1a18862a519e54b2fd0fc8bbfd6890376898a6c0891dd82e9f \ - --hash=sha256:bf50cd79a75d181c9181df03572cdce0fbb75cc353bc350712073108cba98de5 \ - --hash=sha256:bff1b4290a66b490a2f4719358c0cdcd9bafb6b8f061e45c7a2460866bf50c2e \ - --hash=sha256:c061bb86a71b42465156a3ee7bd58c8c2ceacdbeb95d05a99893e08b8467359a \ - --hash=sha256:c8b29db45f8fe46ad280a7294f5c3ec36dbac9491f2d1c17345be8e69cc5928f \ - --hash=sha256:ce409136744f6521e39fd8e2a24c53fa18ad67aa5bc7c2cf83645cce5b5c4e50 \ - --hash=sha256:d050b3361367a06d752db6ead6e7edeb0009be66bc3bae0ee9d97fb326badc2a \ - --hash=sha256:d283d37a890ba4c1ae73ffadf8046435c76e7bc2247bbb63c00bd1a709c6544b \ - --hash=sha256:d9fad5155d72433c921b782e58892377c44bd6252b5af2f67f16b194987338a4 \ - --hash=sha256:daa4ee5a243f0f20d528d939d06670a298dd39b1ad5f8a72a4275124a7819eff \ - --hash=sha256:db0b55e0f3cc0be60c1f19efdde9a637c32740486004f20d1cff53c3c0ece4d2 \ - --hash=sha256:e61659ba32cf2cf1481e575d0462554625196a1f2fc06a1c777d3f48e8865d46 \ - --hash=sha256:ea3d8a3d18833cf4304cd2fc9cbb1efe188ca9b5efef2bdac7adc20594a0e46b \ - --hash=sha256:ec6a563cff360b50eed26f13adc43e61bc0c04d94b8be985e6fb24b81f6dcfdf \ - --hash=sha256:f5dfb42c4604dddc8e4305050aa6deb084540643ed5804d7455b5df8fe16f5e5 \ - --hash=sha256:fa173ec60341d6bb97a89f5ea19c85c5643c1e7dedebc22f5181eb73573142c5 \ - --hash=sha256:fa9db3f79de01457b03d4f01b34cf91bc0048eb2c3846ff26f66687c2f6d16ab \ - --hash=sha256:fce659a462a1be54d2ffcacea5e3ba2d74daa74f30f5f143fe0c58636e355fdd \ - --hash=sha256:ffee1f21e5ef0d712f9033568f8344d5da8cc2869dbd08d87c84656e6a2d2f68 +mako==1.3.6 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:9ec3a1583713479fae654f83ed9fa8c9a4c16b7bb0daba0e6bbebff50c0d983d \ + --hash=sha256:a91198468092a2f1a0de86ca92690fb0cfc43ca90ee17e15d93662b4c04b241a +markupsafe==3.0.2 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:0bff5e0ae4ef2e1ae4fdf2dfd5b76c75e5c2fa4132d05fc1b0dabcd20c7e28c4 \ + --hash=sha256:0f4ca02bea9a23221c0182836703cbf8930c5e9454bacce27e767509fa286a30 \ + --hash=sha256:1225beacc926f536dc82e45f8a4d68502949dc67eea90eab715dea3a21c1b5f0 \ + --hash=sha256:131a3c7689c85f5ad20f9f6fb1b866f402c445b220c19fe4308c0b147ccd2ad9 \ + --hash=sha256:15ab75ef81add55874e7ab7055e9c397312385bd9ced94920f2802310c930396 \ + --hash=sha256:1a9d3f5f0901fdec14d8d2f66ef7d035f2157240a433441719ac9a3fba440b13 \ + --hash=sha256:1c99d261bd2d5f6b59325c92c73df481e05e57f19837bdca8413b9eac4bd8028 \ + --hash=sha256:1e084f686b92e5b83186b07e8a17fc09e38fff551f3602b249881fec658d3eca \ + --hash=sha256:2181e67807fc2fa785d0592dc2d6206c019b9502410671cc905d132a92866557 \ + --hash=sha256:2cb8438c3cbb25e220c2ab33bb226559e7afb3baec11c4f218ffa7308603c832 \ + --hash=sha256:3169b1eefae027567d1ce6ee7cae382c57fe26e82775f460f0b2778beaad66c0 \ + --hash=sha256:3809ede931876f5b2ec92eef964286840ed3540dadf803dd570c3b7e13141a3b \ + --hash=sha256:38a9ef736c01fccdd6600705b09dc574584b89bea478200c5fbf112a6b0d5579 \ + --hash=sha256:3d79d162e7be8f996986c064d1c7c817f6df3a77fe3d6859f6f9e7be4b8c213a \ + --hash=sha256:444dcda765c8a838eaae23112db52f1efaf750daddb2d9ca300bcae1039adc5c \ + --hash=sha256:48032821bbdf20f5799ff537c7ac3d1fba0ba032cfc06194faffa8cda8b560ff \ + --hash=sha256:4aa4e5faecf353ed117801a068ebab7b7e09ffb6e1d5e412dc852e0da018126c \ + --hash=sha256:52305740fe773d09cffb16f8ed0427942901f00adedac82ec8b67752f58a1b22 \ + --hash=sha256:569511d3b58c8791ab4c2e1285575265991e6d8f8700c7be0e88f86cb0672094 \ + --hash=sha256:57cb5a3cf367aeb1d316576250f65edec5bb3be939e9247ae594b4bcbc317dfb \ + --hash=sha256:5b02fb34468b6aaa40dfc198d813a641e3a63b98c2b05a16b9f80b7ec314185e \ + --hash=sha256:6381026f158fdb7c72a168278597a5e3a5222e83ea18f543112b2662a9b699c5 \ + --hash=sha256:6af100e168aa82a50e186c82875a5893c5597a0c1ccdb0d8b40240b1f28b969a \ + --hash=sha256:6c89876f41da747c8d3677a2b540fb32ef5715f97b66eeb0c6b66f5e3ef6f59d \ + --hash=sha256:6e296a513ca3d94054c2c881cc913116e90fd030ad1c656b3869762b754f5f8a \ + --hash=sha256:70a87b411535ccad5ef2f1df5136506a10775d267e197e4cf531ced10537bd6b \ + --hash=sha256:7e94c425039cde14257288fd61dcfb01963e658efbc0ff54f5306b06054700f8 \ + --hash=sha256:846ade7b71e3536c4e56b386c2a47adf5741d2d8b94ec9dc3e92e5e1ee1e2225 \ + --hash=sha256:88416bd1e65dcea10bc7569faacb2c20ce071dd1f87539ca2ab364bf6231393c \ + --hash=sha256:88b49a3b9ff31e19998750c38e030fc7bb937398b1f78cfa599aaef92d693144 \ + --hash=sha256:8c4e8c3ce11e1f92f6536ff07154f9d49677ebaaafc32db9db4620bc11ed480f \ + --hash=sha256:8e06879fc22a25ca47312fbe7c8264eb0b662f6db27cb2d3bbbc74b1df4b9b87 \ + --hash=sha256:9025b4018f3a1314059769c7bf15441064b2207cb3f065e6ea1e7359cb46db9d \ + --hash=sha256:93335ca3812df2f366e80509ae119189886b0f3c2b81325d39efdb84a1e2ae93 \ + --hash=sha256:9778bd8ab0a994ebf6f84c2b949e65736d5575320a17ae8984a77fab08db94cf \ + --hash=sha256:9e2d922824181480953426608b81967de705c3cef4d1af983af849d7bd619158 \ + --hash=sha256:a123e330ef0853c6e822384873bef7507557d8e4a082961e1defa947aa59ba84 \ + --hash=sha256:a904af0a6162c73e3edcb969eeeb53a63ceeb5d8cf642fade7d39e7963a22ddb \ + --hash=sha256:ad10d3ded218f1039f11a75f8091880239651b52e9bb592ca27de44eed242a48 \ + --hash=sha256:b424c77b206d63d500bcb69fa55ed8d0e6a3774056bdc4839fc9298a7edca171 \ + --hash=sha256:b5a6b3ada725cea8a5e634536b1b01c30bcdcd7f9c6fff4151548d5bf6b3a36c \ + --hash=sha256:ba8062ed2cf21c07a9e295d5b8a2a5ce678b913b45fdf68c32d95d6c1291e0b6 \ + --hash=sha256:ba9527cdd4c926ed0760bc301f6728ef34d841f405abf9d4f959c478421e4efd \ + --hash=sha256:bbcb445fa71794da8f178f0f6d66789a28d7319071af7a496d4d507ed566270d \ + --hash=sha256:bcf3e58998965654fdaff38e58584d8937aa3096ab5354d493c77d1fdd66d7a1 \ + --hash=sha256:c0ef13eaeee5b615fb07c9a7dadb38eac06a0608b41570d8ade51c56539e509d \ + --hash=sha256:cabc348d87e913db6ab4aa100f01b08f481097838bdddf7c7a84b7575b7309ca \ + --hash=sha256:cdb82a876c47801bb54a690c5ae105a46b392ac6099881cdfb9f6e95e4014c6a \ + --hash=sha256:cfad01eed2c2e0c01fd0ecd2ef42c492f7f93902e39a42fc9ee1692961443a29 \ + --hash=sha256:d16a81a06776313e817c951135cf7340a3e91e8c1ff2fac444cfd75fffa04afe \ + --hash=sha256:d8213e09c917a951de9d09ecee036d5c7d36cb6cb7dbaece4c71a60d79fb9798 \ + --hash=sha256:e07c3764494e3776c602c1e78e298937c3315ccc9043ead7e685b7f2b8d47b3c \ + --hash=sha256:e17c96c14e19278594aa4841ec148115f9c7615a47382ecb6b82bd8fea3ab0c8 \ + --hash=sha256:e444a31f8db13eb18ada366ab3cf45fd4b31e4db1236a4448f68778c1d1a5a2f \ + --hash=sha256:e6a2a455bd412959b57a172ce6328d2dd1f01cb2135efda2e4576e8a23fa3b0f \ + --hash=sha256:eaa0a10b7f72326f1372a713e73c3f739b524b3af41feb43e4921cb529f5929a \ + --hash=sha256:eb7972a85c54febfb25b5c4b4f3af4dcc731994c7da0d8a0b4a6eb0640e1d178 \ + --hash=sha256:ee55d3edf80167e48ea11a923c7386f4669df67d7994554387f84e7d8b0a2bf0 \ + --hash=sha256:f3818cb119498c0678015754eba762e0d61e5b52d34c8b13d770f0719f7b1d79 \ + --hash=sha256:f8b3d067f2e40fe93e1ccdd6b2e1d16c43140e76f02fb1319a05cf2b79d99430 \ + --hash=sha256:fcabf5ff6eea076f859677f5f0b6b5c1a51e70a376b0579e0eadef8db48c6b50 maxminddb==2.5.1 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:0702da59b9670a72761b65cb1a52bc3032d8f6799bdab641cb8350ad5740580b \ --hash=sha256:0a21abd85e10e5e0f60244b49c3db17e7e48befd4972e62a62833d91e2acbb49 \ @@ -687,113 +690,14 @@ maxminddb==2.5.1 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:fad45cd2f2e3c5fbebacb8d172a60fb22443222e549bf740a0bc7eeb849e5ce7 \ --hash=sha256:fbd01fc7d7b5b2befe914e8cdb5ed3a1c5476e57b765197cceff8d897f33d012 \ --hash=sha256:fe0af3ba9e1a78ed5f2ad32fc18d18b78ef233e7d0c627e1a77a525a7eb0c241 -mdurl==0.1.2 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8 \ - --hash=sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba -msgpack==1.0.8 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:00e073efcba9ea99db5acef3959efa45b52bc67b61b00823d2a1a6944bf45982 \ - --hash=sha256:0726c282d188e204281ebd8de31724b7d749adebc086873a59efb8cf7ae27df3 \ - --hash=sha256:0ceea77719d45c839fd73abcb190b8390412a890df2f83fb8cf49b2a4b5c2f40 \ - --hash=sha256:114be227f5213ef8b215c22dde19532f5da9652e56e8ce969bf0a26d7c419fee \ - --hash=sha256:13577ec9e247f8741c84d06b9ece5f654920d8365a4b636ce0e44f15e07ec693 \ - --hash=sha256:1876b0b653a808fcd50123b953af170c535027bf1d053b59790eebb0aeb38950 \ - --hash=sha256:1ab0bbcd4d1f7b6991ee7c753655b481c50084294218de69365f8f1970d4c151 \ - --hash=sha256:1cce488457370ffd1f953846f82323cb6b2ad2190987cd4d70b2713e17268d24 \ - --hash=sha256:26ee97a8261e6e35885c2ecd2fd4a6d38252246f94a2aec23665a4e66d066305 \ - --hash=sha256:3528807cbbb7f315bb81959d5961855e7ba52aa60a3097151cb21956fbc7502b \ - --hash=sha256:374a8e88ddab84b9ada695d255679fb99c53513c0a51778796fcf0944d6c789c \ - --hash=sha256:376081f471a2ef24828b83a641a02c575d6103a3ad7fd7dade5486cad10ea659 \ - --hash=sha256:3923a1778f7e5ef31865893fdca12a8d7dc03a44b33e2a5f3295416314c09f5d \ - --hash=sha256:4916727e31c28be8beaf11cf117d6f6f188dcc36daae4e851fee88646f5b6b18 \ - --hash=sha256:493c5c5e44b06d6c9268ce21b302c9ca055c1fd3484c25ba41d34476c76ee746 \ - --hash=sha256:505fe3d03856ac7d215dbe005414bc28505d26f0c128906037e66d98c4e95868 \ - --hash=sha256:5845fdf5e5d5b78a49b826fcdc0eb2e2aa7191980e3d2cfd2a30303a74f212e2 \ - --hash=sha256:5c330eace3dd100bdb54b5653b966de7f51c26ec4a7d4e87132d9b4f738220ba \ - --hash=sha256:5dbf059fb4b7c240c873c1245ee112505be27497e90f7c6591261c7d3c3a8228 \ - --hash=sha256:5e390971d082dba073c05dbd56322427d3280b7cc8b53484c9377adfbae67dc2 \ - --hash=sha256:5fbb160554e319f7b22ecf530a80a3ff496d38e8e07ae763b9e82fadfe96f273 \ - --hash=sha256:64d0fcd436c5683fdd7c907eeae5e2cbb5eb872fafbc03a43609d7941840995c \ - --hash=sha256:69284049d07fce531c17404fcba2bb1df472bc2dcdac642ae71a2d079d950653 \ - --hash=sha256:6a0e76621f6e1f908ae52860bdcb58e1ca85231a9b0545e64509c931dd34275a \ - --hash=sha256:73ee792784d48aa338bba28063e19a27e8d989344f34aad14ea6e1b9bd83f596 \ - --hash=sha256:74398a4cf19de42e1498368c36eed45d9528f5fd0155241e82c4082b7e16cffd \ - --hash=sha256:7938111ed1358f536daf311be244f34df7bf3cdedb3ed883787aca97778b28d8 \ - --hash=sha256:82d92c773fbc6942a7a8b520d22c11cfc8fd83bba86116bfcf962c2f5c2ecdaa \ - --hash=sha256:83b5c044f3eff2a6534768ccfd50425939e7a8b5cf9a7261c385de1e20dcfc85 \ - --hash=sha256:8db8e423192303ed77cff4dce3a4b88dbfaf43979d280181558af5e2c3c71afc \ - --hash=sha256:9517004e21664f2b5a5fd6333b0731b9cf0817403a941b393d89a2f1dc2bd836 \ - --hash=sha256:95c02b0e27e706e48d0e5426d1710ca78e0f0628d6e89d5b5a5b91a5f12274f3 \ - --hash=sha256:99881222f4a8c2f641f25703963a5cefb076adffd959e0558dc9f803a52d6a58 \ - --hash=sha256:9ee32dcb8e531adae1f1ca568822e9b3a738369b3b686d1477cbc643c4a9c128 \ - --hash=sha256:a22e47578b30a3e199ab067a4d43d790249b3c0587d9a771921f86250c8435db \ - --hash=sha256:b5505774ea2a73a86ea176e8a9a4a7c8bf5d521050f0f6f8426afe798689243f \ - --hash=sha256:bd739c9251d01e0279ce729e37b39d49a08c0420d3fee7f2a4968c0576678f77 \ - --hash=sha256:d16a786905034e7e34098634b184a7d81f91d4c3d246edc6bd7aefb2fd8ea6ad \ - --hash=sha256:d3420522057ebab1728b21ad473aa950026d07cb09da41103f8e597dfbfaeb13 \ - --hash=sha256:d56fd9f1f1cdc8227d7b7918f55091349741904d9520c65f0139a9755952c9e8 \ - --hash=sha256:d661dc4785affa9d0edfdd1e59ec056a58b3dbb9f196fa43587f3ddac654ac7b \ - --hash=sha256:dfe1f0f0ed5785c187144c46a292b8c34c1295c01da12e10ccddfc16def4448a \ - --hash=sha256:e1dd7839443592d00e96db831eddb4111a2a81a46b028f0facd60a09ebbdd543 \ - --hash=sha256:e2872993e209f7ed04d963e4b4fbae72d034844ec66bc4ca403329db2074377b \ - --hash=sha256:e2f879ab92ce502a1e65fce390eab619774dda6a6ff719718069ac94084098ce \ - --hash=sha256:e3aa7e51d738e0ec0afbed661261513b38b3014754c9459508399baf14ae0c9d \ - --hash=sha256:e532dbd6ddfe13946de050d7474e3f5fb6ec774fbb1a188aaf469b08cf04189a \ - --hash=sha256:e6b7842518a63a9f17107eb176320960ec095a8ee3b4420b5f688e24bf50c53c \ - --hash=sha256:e75753aeda0ddc4c28dce4c32ba2f6ec30b1b02f6c0b14e547841ba5b24f753f \ - --hash=sha256:eadb9f826c138e6cf3c49d6f8de88225a3c0ab181a9b4ba792e006e5292d150e \ - --hash=sha256:ed59dd52075f8fc91da6053b12e8c89e37aa043f8986efd89e61fae69dc1b011 \ - --hash=sha256:ef254a06bcea461e65ff0373d8a0dd1ed3aa004af48839f002a0c994a6f72d04 \ - --hash=sha256:f3709997b228685fe53e8c433e2df9f0cdb5f4542bd5114ed17ac3c0129b0480 \ - --hash=sha256:f51bab98d52739c50c56658cc303f190785f9a2cd97b823357e7aeae54c8f68a \ - --hash=sha256:f9904e24646570539a8950400602d66d2b2c492b9010ea7e965025cb71d0c86d \ - --hash=sha256:f9af38a89b6a5c04b7d18c492c8ccf2aee7048aff1ce8437c4683bb5a1df893d -msgspec==0.18.6 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:06acbd6edf175bee0e36295d6b0302c6de3aaf61246b46f9549ca0041a9d7177 \ - --hash=sha256:0e24539b25c85c8f0597274f11061c102ad6b0c56af053373ba4629772b407be \ - --hash=sha256:1003c20bfe9c6114cc16ea5db9c5466e49fae3d7f5e2e59cb70693190ad34da0 \ - --hash=sha256:1a76b60e501b3932782a9da039bd1cd552b7d8dec54ce38332b87136c64852dd \ - --hash=sha256:37f67c1d81272131895bb20d388dd8d341390acd0e192a55ab02d4d6468b434c \ - --hash=sha256:3ac4dd63fd5309dd42a8c8c36c1563531069152be7819518be0a9d03be9788e4 \ - --hash=sha256:40a4df891676d9c28a67c2cc39947c33de516335680d1316a89e8f7218660410 \ - --hash=sha256:41cf758d3f40428c235c0f27bc6f322d43063bc32da7b9643e3f805c21ed57b4 \ - --hash=sha256:46eb2f6b22b0e61c137e65795b97dc515860bf6ec761d8fb65fdb62aa094ba61 \ - --hash=sha256:6aa85198f8f154cf35d6f979998f6dadd3dc46a8a8c714632f53f5d65b315c07 \ - --hash=sha256:7481355a1adcf1f08dedd9311193c674ffb8bf7b79314b4314752b89a2cf7f1c \ - --hash=sha256:77f30b0234eceeff0f651119b9821ce80949b4d667ad38f3bfed0d0ebf9d6d8f \ - --hash=sha256:9080eb12b8f59e177bd1eb5c21e24dd2ba2fa88a1dbc9a98e05ad7779b54c681 \ - --hash=sha256:974d3520fcc6b824a6dedbdf2b411df31a73e6e7414301abac62e6b8d03791b4 \ - --hash=sha256:9da21f804c1a1471f26d32b5d9bc0480450ea77fbb8d9db431463ab64aaac2cf \ - --hash=sha256:a59fc3b4fcdb972d09138cb516dbde600c99d07c38fd9372a6ef500d2d031b4e \ - --hash=sha256:a6896f4cd5b4b7d688018805520769a8446df911eb93b421c6c68155cdf9dd5a \ - --hash=sha256:ad237100393f637b297926cae1868b0d500f764ccd2f0623a380e2bcfb2809ca \ - --hash=sha256:b5c390b0b0b7da879520d4ae26044d74aeee5144f83087eb7842ba59c02bc090 \ - --hash=sha256:c3232fabacef86fe8323cecbe99abbc5c02f7698e3f5f2e248e3480b66a3596b \ - --hash=sha256:c61ee4d3be03ea9cd089f7c8e36158786cd06e51fbb62529276452bbf2d52ece \ - --hash=sha256:c8355b55c80ac3e04885d72db515817d9fbb0def3bab936bba104e99ad22cf46 \ - --hash=sha256:cc001cf39becf8d2dcd3f413a4797c55009b3a3cdbf78a8bf5a7ca8fdb76032c \ - --hash=sha256:ce13981bfa06f5eb126a3a5a38b1976bddb49a36e4f46d8e6edecf33ccf11df1 \ - --hash=sha256:d0feb7a03d971c1c0353de1a8fe30bb6579c2dc5ccf29b5f7c7ab01172010492 \ - --hash=sha256:d5351afb216b743df4b6b147691523697ff3a2fc5f3d54f771e91219f5c23aaa \ - --hash=sha256:d70cb3d00d9f4de14d0b31d38dfe60c88ae16f3182988246a9861259c6722af6 \ - --hash=sha256:d86f5071fe33e19500920333c11e2267a31942d18fed4d9de5bc2fbab267d28c \ - --hash=sha256:db1d8626748fa5d29bbd15da58b2d73af25b10aa98abf85aab8028119188ed57 \ - --hash=sha256:e3b524df6ea9998bbc99ea6ee4d0276a101bcc1aa8d14887bb823914d9f60d07 \ - --hash=sha256:e77e56ffe2701e83a96e35770c6adb655ffc074d530018d1b584a8e635b4f36f \ - --hash=sha256:e97dec6932ad5e3ee1e3c14718638ba333befc45e0661caa57033cd4cc489466 \ - --hash=sha256:f7d9faed6dfff654a9ca7d9b0068456517f63dbc3aa704a527f493b9200b210a \ - --hash=sha256:fac5834e14ac4da1fca373753e0c4ec9c8069d1fe5f534fa5208453b6065d5be \ - --hash=sha256:fd62e5818731a66aaa8e9b0a1e5543dc979a46278da01e85c3c9a1a4f047ef7e \ - --hash=sha256:fda4c357145cf0b760000c4ad597e19b53adf01382b711f281720a10a0fe72b7 msoffcrypto-tool==5.4.2 ; python_version >= "3.10" and python_version < "4.0" and platform_python_implementation != "PyPy" or python_version >= "3.10" and python_version < "4.0" and (platform_system != "Windows" and platform_system != "Darwin") \ --hash=sha256:274fe2181702d1e5a107ec1b68a4c9fea997a44972ae1cc9ae0cb4f6a50fef0e \ --hash=sha256:44b545adba0407564a0cc3d6dde6ca36b7c0fdf352b85bca51618fa1d4817370 -nanobind==2.1.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:a613a2ce750fee63f03dc8a36593be2bdc2929cb4cea56b38fafeb74b85c3a5f +nanobind==2.2.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:138685ec9c5de4f57dd02d715b89ffcbcabae39c4e36b8b2c40eea2f1aa2f0d7 \ + --hash=sha256:53fa7a6227bddecaa4a0710e0b8dc18fad4c8ded7a0a31d6eddcf68009ead603 netstruct==1.1.2 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:70b6a5c73f5bbc7ab57b019369642adfb34dd8af41b948c400ce95f952b7df9a -networkx==3.1 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:4f33f68cb2afcf86f28a45f43efc27a9386b535d567d2127f8f61d51dec58d36 \ - --hash=sha256:de346335408f84de0eada6ff9fafafff9bcda11f0a0dfaa931133debb146ab61 oauthlib==3.2.2 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:8139f29aac13e25d502680e9e19963e83f16838d48a0d71c287fe40e7067fbca \ --hash=sha256:9859c40929662bec5d64f34d01c99e093149682a3f38915dc0655d5a633dd918 @@ -868,99 +772,82 @@ pebble==4.6.3 ; python_version >= "3.10" and python_version < "4.0" \ pefile==2024.8.26 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:3ff6c5d8b43e8c37bb6e6dd5085658d658a7a0bdcd20b6a07b1fcfc1c4e9d632 \ --hash=sha256:76f8b485dcd3b1bb8166f1128d395fa3d87af26360c2358fb75b80019b957c6f -pillow==10.4.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:02a2be69f9c9b8c1e97cf2713e789d4e398c751ecfd9967c18d0ce304efbf885 \ - --hash=sha256:030abdbe43ee02e0de642aee345efa443740aa4d828bfe8e2eb11922ea6a21ea \ - --hash=sha256:06b2f7898047ae93fad74467ec3d28fe84f7831370e3c258afa533f81ef7f3df \ - --hash=sha256:0755ffd4a0c6f267cccbae2e9903d95477ca2f77c4fcf3a3a09570001856c8a5 \ - --hash=sha256:0a9ec697746f268507404647e531e92889890a087e03681a3606d9b920fbee3c \ - --hash=sha256:0ae24a547e8b711ccaaf99c9ae3cd975470e1a30caa80a6aaee9a2f19c05701d \ - --hash=sha256:134ace6dc392116566980ee7436477d844520a26a4b1bd4053f6f47d096997fd \ - --hash=sha256:166c1cd4d24309b30d61f79f4a9114b7b2313d7450912277855ff5dfd7cd4a06 \ - --hash=sha256:1b5dea9831a90e9d0721ec417a80d4cbd7022093ac38a568db2dd78363b00908 \ - --hash=sha256:1d846aea995ad352d4bdcc847535bd56e0fd88d36829d2c90be880ef1ee4668a \ - --hash=sha256:1ef61f5dd14c300786318482456481463b9d6b91ebe5ef12f405afbba77ed0be \ - --hash=sha256:297e388da6e248c98bc4a02e018966af0c5f92dfacf5a5ca22fa01cb3179bca0 \ - --hash=sha256:298478fe4f77a4408895605f3482b6cc6222c018b2ce565c2b6b9c354ac3229b \ - --hash=sha256:29dbdc4207642ea6aad70fbde1a9338753d33fb23ed6956e706936706f52dd80 \ - --hash=sha256:2db98790afc70118bd0255c2eeb465e9767ecf1f3c25f9a1abb8ffc8cfd1fe0a \ - --hash=sha256:32cda9e3d601a52baccb2856b8ea1fc213c90b340c542dcef77140dfa3278a9e \ - --hash=sha256:37fb69d905be665f68f28a8bba3c6d3223c8efe1edf14cc4cfa06c241f8c81d9 \ - --hash=sha256:416d3a5d0e8cfe4f27f574362435bc9bae57f679a7158e0096ad2beb427b8696 \ - --hash=sha256:43efea75eb06b95d1631cb784aa40156177bf9dd5b4b03ff38979e048258bc6b \ - --hash=sha256:4b35b21b819ac1dbd1233317adeecd63495f6babf21b7b2512d244ff6c6ce309 \ - --hash=sha256:4d9667937cfa347525b319ae34375c37b9ee6b525440f3ef48542fcf66f2731e \ - --hash=sha256:5161eef006d335e46895297f642341111945e2c1c899eb406882a6c61a4357ab \ - --hash=sha256:543f3dc61c18dafb755773efc89aae60d06b6596a63914107f75459cf984164d \ - --hash=sha256:551d3fd6e9dc15e4c1eb6fc4ba2b39c0c7933fa113b220057a34f4bb3268a060 \ - --hash=sha256:59291fb29317122398786c2d44427bbd1a6d7ff54017075b22be9d21aa59bd8d \ - --hash=sha256:5b001114dd152cfd6b23befeb28d7aee43553e2402c9f159807bf55f33af8a8d \ - --hash=sha256:5b4815f2e65b30f5fbae9dfffa8636d992d49705723fe86a3661806e069352d4 \ - --hash=sha256:5dc6761a6efc781e6a1544206f22c80c3af4c8cf461206d46a1e6006e4429ff3 \ - --hash=sha256:5e84b6cc6a4a3d76c153a6b19270b3526a5a8ed6b09501d3af891daa2a9de7d6 \ - --hash=sha256:6209bb41dc692ddfee4942517c19ee81b86c864b626dbfca272ec0f7cff5d9fb \ - --hash=sha256:673655af3eadf4df6b5457033f086e90299fdd7a47983a13827acf7459c15d94 \ - --hash=sha256:6c762a5b0997f5659a5ef2266abc1d8851ad7749ad9a6a5506eb23d314e4f46b \ - --hash=sha256:7086cc1d5eebb91ad24ded9f58bec6c688e9f0ed7eb3dbbf1e4800280a896496 \ - --hash=sha256:73664fe514b34c8f02452ffb73b7a92c6774e39a647087f83d67f010eb9a0cf0 \ - --hash=sha256:76a911dfe51a36041f2e756b00f96ed84677cdeb75d25c767f296c1c1eda1319 \ - --hash=sha256:780c072c2e11c9b2c7ca37f9a2ee8ba66f44367ac3e5c7832afcfe5104fd6d1b \ - --hash=sha256:7928ecbf1ece13956b95d9cbcfc77137652b02763ba384d9ab508099a2eca856 \ - --hash=sha256:7970285ab628a3779aecc35823296a7869f889b8329c16ad5a71e4901a3dc4ef \ - --hash=sha256:7a8d4bade9952ea9a77d0c3e49cbd8b2890a399422258a77f357b9cc9be8d680 \ - --hash=sha256:7c1ee6f42250df403c5f103cbd2768a28fe1a0ea1f0f03fe151c8741e1469c8b \ - --hash=sha256:7dfecdbad5c301d7b5bde160150b4db4c659cee2b69589705b6f8a0c509d9f42 \ - --hash=sha256:812f7342b0eee081eaec84d91423d1b4650bb9828eb53d8511bcef8ce5aecf1e \ - --hash=sha256:866b6942a92f56300012f5fbac71f2d610312ee65e22f1aa2609e491284e5597 \ - --hash=sha256:86dcb5a1eb778d8b25659d5e4341269e8590ad6b4e8b44d9f4b07f8d136c414a \ - --hash=sha256:87dd88ded2e6d74d31e1e0a99a726a6765cda32d00ba72dc37f0651f306daaa8 \ - --hash=sha256:8bc1a764ed8c957a2e9cacf97c8b2b053b70307cf2996aafd70e91a082e70df3 \ - --hash=sha256:8d4d5063501b6dd4024b8ac2f04962d661222d120381272deea52e3fc52d3736 \ - --hash=sha256:8f0aef4ef59694b12cadee839e2ba6afeab89c0f39a3adc02ed51d109117b8da \ - --hash=sha256:930044bb7679ab003b14023138b50181899da3f25de50e9dbee23b61b4de2126 \ - --hash=sha256:950be4d8ba92aca4b2bb0741285a46bfae3ca699ef913ec8416c1b78eadd64cd \ - --hash=sha256:961a7293b2457b405967af9c77dcaa43cc1a8cd50d23c532e62d48ab6cdd56f5 \ - --hash=sha256:9b885f89040bb8c4a1573566bbb2f44f5c505ef6e74cec7ab9068c900047f04b \ - --hash=sha256:9f4727572e2918acaa9077c919cbbeb73bd2b3ebcfe033b72f858fc9fbef0026 \ - --hash=sha256:a02364621fe369e06200d4a16558e056fe2805d3468350df3aef21e00d26214b \ - --hash=sha256:a985e028fc183bf12a77a8bbf36318db4238a3ded7fa9df1b9a133f1cb79f8fc \ - --hash=sha256:ac1452d2fbe4978c2eec89fb5a23b8387aba707ac72810d9490118817d9c0b46 \ - --hash=sha256:b15e02e9bb4c21e39876698abf233c8c579127986f8207200bc8a8f6bb27acf2 \ - --hash=sha256:b2724fdb354a868ddf9a880cb84d102da914e99119211ef7ecbdc613b8c96b3c \ - --hash=sha256:bbc527b519bd3aa9d7f429d152fea69f9ad37c95f0b02aebddff592688998abe \ - --hash=sha256:bcd5e41a859bf2e84fdc42f4edb7d9aba0a13d29a2abadccafad99de3feff984 \ - --hash=sha256:bd2880a07482090a3bcb01f4265f1936a903d70bc740bfcb1fd4e8a2ffe5cf5a \ - --hash=sha256:bee197b30783295d2eb680b311af15a20a8b24024a19c3a26431ff83eb8d1f70 \ - --hash=sha256:bf2342ac639c4cf38799a44950bbc2dfcb685f052b9e262f446482afaf4bffca \ - --hash=sha256:c76e5786951e72ed3686e122d14c5d7012f16c8303a674d18cdcd6d89557fc5b \ - --hash=sha256:cbed61494057c0f83b83eb3a310f0bf774b09513307c434d4366ed64f4128a91 \ - --hash=sha256:cfdd747216947628af7b259d274771d84db2268ca062dd5faf373639d00113a3 \ - --hash=sha256:d7480af14364494365e89d6fddc510a13e5a2c3584cb19ef65415ca57252fb84 \ - --hash=sha256:dbc6ae66518ab3c5847659e9988c3b60dc94ffb48ef9168656e0019a93dbf8a1 \ - --hash=sha256:dc3e2db6ba09ffd7d02ae9141cfa0ae23393ee7687248d46a7507b75d610f4f5 \ - --hash=sha256:dfe91cb65544a1321e631e696759491ae04a2ea11d36715eca01ce07284738be \ - --hash=sha256:e4d49b85c4348ea0b31ea63bc75a9f3857869174e2bf17e7aba02945cd218e6f \ - --hash=sha256:e4db64794ccdf6cb83a59d73405f63adbe2a1887012e308828596100a0b2f6cc \ - --hash=sha256:e553cad5179a66ba15bb18b353a19020e73a7921296a7979c4a2b7f6a5cd57f9 \ - --hash=sha256:e88d5e6ad0d026fba7bdab8c3f225a69f063f116462c49892b0149e21b6c0a0e \ - --hash=sha256:ecd85a8d3e79cd7158dec1c9e5808e821feea088e2f69a974db5edf84dc53141 \ - --hash=sha256:f5b92f4d70791b4a67157321c4e8225d60b119c5cc9aee8ecf153aace4aad4ef \ - --hash=sha256:f5f0c3e969c8f12dd2bb7e0b15d5c468b51e5017e01e2e867335c81903046a22 \ - --hash=sha256:f7baece4ce06bade126fb84b8af1c33439a76d8a6fd818970215e0560ca28c27 \ - --hash=sha256:ff25afb18123cea58a591ea0244b92eb1e61a1fd497bf6d6384f09bc3262ec3e \ - --hash=sha256:ff337c552345e95702c5fde3158acb0625111017d0e5f24bf3acdb9cc16b90d1 -protobuf==5.28.2 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:2c69461a7fcc8e24be697624c09a839976d82ae75062b11a0972e41fd2cd9132 \ - --hash=sha256:35cfcb15f213449af7ff6198d6eb5f739c37d7e4f1c09b5d0641babf2cc0c68f \ - --hash=sha256:52235802093bd8a2811abbe8bf0ab9c5f54cca0a751fdd3f6ac2a21438bffece \ - --hash=sha256:59379674ff119717404f7454647913787034f03fe7049cbef1d74a97bb4593f0 \ - --hash=sha256:5e8a95246d581eef20471b5d5ba010d55f66740942b95ba9b872d918c459452f \ - --hash=sha256:87317e9bcda04a32f2ee82089a204d3a2f0d3c8aeed16568c7daf4756e4f1fe0 \ - --hash=sha256:8ddc60bf374785fb7cb12510b267f59067fa10087325b8e1855b898a0d81d276 \ - --hash=sha256:a8b9403fc70764b08d2f593ce44f1d2920c5077bf7d311fefec999f8c40f78b7 \ - --hash=sha256:c0ea0123dac3399a2eeb1a1443d82b7afc9ff40241433296769f7da42d142ec3 \ - --hash=sha256:ca53faf29896c526863366a52a8f4d88e69cd04ec9571ed6082fa117fac3ab36 \ - --hash=sha256:eeea10f3dc0ac7e6b4933d32db20662902b4ab81bf28df12218aa389e9c2102d +pillow==11.0.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:00177a63030d612148e659b55ba99527803288cea7c75fb05766ab7981a8c1b7 \ + --hash=sha256:006bcdd307cc47ba43e924099a038cbf9591062e6c50e570819743f5607404f5 \ + --hash=sha256:084a07ef0821cfe4858fe86652fffac8e187b6ae677e9906e192aafcc1b69903 \ + --hash=sha256:0ae08bd8ffc41aebf578c2af2f9d8749d91f448b3bfd41d7d9ff573d74f2a6b2 \ + --hash=sha256:0e038b0745997c7dcaae350d35859c9715c71e92ffb7e0f4a8e8a16732150f38 \ + --hash=sha256:1187739620f2b365de756ce086fdb3604573337cc28a0d3ac4a01ab6b2d2a6d2 \ + --hash=sha256:16095692a253047fe3ec028e951fa4221a1f3ed3d80c397e83541a3037ff67c9 \ + --hash=sha256:1a61b54f87ab5786b8479f81c4b11f4d61702830354520837f8cc791ebba0f5f \ + --hash=sha256:1c1d72714f429a521d8d2d018badc42414c3077eb187a59579f28e4270b4b0fc \ + --hash=sha256:1e2688958a840c822279fda0086fec1fdab2f95bf2b717b66871c4ad9859d7e8 \ + --hash=sha256:20ec184af98a121fb2da42642dea8a29ec80fc3efbaefb86d8fdd2606619045d \ + --hash=sha256:21a0d3b115009ebb8ac3d2ebec5c2982cc693da935f4ab7bb5c8ebe2f47d36f2 \ + --hash=sha256:224aaa38177597bb179f3ec87eeefcce8e4f85e608025e9cfac60de237ba6316 \ + --hash=sha256:2679d2258b7f1192b378e2893a8a0a0ca472234d4c2c0e6bdd3380e8dfa21b6a \ + --hash=sha256:27a7860107500d813fcd203b4ea19b04babe79448268403172782754870dac25 \ + --hash=sha256:290f2cc809f9da7d6d622550bbf4c1e57518212da51b6a30fe8e0a270a5b78bd \ + --hash=sha256:2e46773dc9f35a1dd28bd6981332fd7f27bec001a918a72a79b4133cf5291dba \ + --hash=sha256:3107c66e43bda25359d5ef446f59c497de2b5ed4c7fdba0894f8d6cf3822dafc \ + --hash=sha256:375b8dd15a1f5d2feafff536d47e22f69625c1aa92f12b339ec0b2ca40263273 \ + --hash=sha256:45c566eb10b8967d71bf1ab8e4a525e5a93519e29ea071459ce517f6b903d7fa \ + --hash=sha256:499c3a1b0d6fc8213519e193796eb1a86a1be4b1877d678b30f83fd979811d1a \ + --hash=sha256:4ad70c4214f67d7466bea6a08061eba35c01b1b89eaa098040a35272a8efb22b \ + --hash=sha256:4b60c9520f7207aaf2e1d94de026682fc227806c6e1f55bba7606d1c94dd623a \ + --hash=sha256:5178952973e588b3f1360868847334e9e3bf49d19e169bbbdfaf8398002419ae \ + --hash=sha256:52a2d8323a465f84faaba5236567d212c3668f2ab53e1c74c15583cf507a0291 \ + --hash=sha256:598b4e238f13276e0008299bd2482003f48158e2b11826862b1eb2ad7c768b97 \ + --hash=sha256:5bd2d3bdb846d757055910f0a59792d33b555800813c3b39ada1829c372ccb06 \ + --hash=sha256:5c39ed17edea3bc69c743a8dd3e9853b7509625c2462532e62baa0732163a904 \ + --hash=sha256:5d203af30149ae339ad1b4f710d9844ed8796e97fda23ffbc4cc472968a47d0b \ + --hash=sha256:5ddbfd761ee00c12ee1be86c9c0683ecf5bb14c9772ddbd782085779a63dd55b \ + --hash=sha256:607bbe123c74e272e381a8d1957083a9463401f7bd01287f50521ecb05a313f8 \ + --hash=sha256:61b887f9ddba63ddf62fd02a3ba7add935d053b6dd7d58998c630e6dbade8527 \ + --hash=sha256:6619654954dc4936fcff82db8eb6401d3159ec6be81e33c6000dfd76ae189947 \ + --hash=sha256:674629ff60030d144b7bca2b8330225a9b11c482ed408813924619c6f302fdbb \ + --hash=sha256:6ec0d5af64f2e3d64a165f490d96368bb5dea8b8f9ad04487f9ab60dc4bb6003 \ + --hash=sha256:6f4dba50cfa56f910241eb7f883c20f1e7b1d8f7d91c750cd0b318bad443f4d5 \ + --hash=sha256:70fbbdacd1d271b77b7721fe3cdd2d537bbbd75d29e6300c672ec6bb38d9672f \ + --hash=sha256:72bacbaf24ac003fea9bff9837d1eedb6088758d41e100c1552930151f677739 \ + --hash=sha256:7326a1787e3c7b0429659e0a944725e1b03eeaa10edd945a86dead1913383944 \ + --hash=sha256:73853108f56df97baf2bb8b522f3578221e56f646ba345a372c78326710d3830 \ + --hash=sha256:73e3a0200cdda995c7e43dd47436c1548f87a30bb27fb871f352a22ab8dcf45f \ + --hash=sha256:75acbbeb05b86bc53cbe7b7e6fe00fbcf82ad7c684b3ad82e3d711da9ba287d3 \ + --hash=sha256:8069c5179902dcdce0be9bfc8235347fdbac249d23bd90514b7a47a72d9fecf4 \ + --hash=sha256:846e193e103b41e984ac921b335df59195356ce3f71dcfd155aa79c603873b84 \ + --hash=sha256:8594f42df584e5b4bb9281799698403f7af489fba84c34d53d1c4bfb71b7c4e7 \ + --hash=sha256:86510e3f5eca0ab87429dd77fafc04693195eec7fd6a137c389c3eeb4cfb77c6 \ + --hash=sha256:8853a3bf12afddfdf15f57c4b02d7ded92c7a75a5d7331d19f4f9572a89c17e6 \ + --hash=sha256:88a58d8ac0cc0e7f3a014509f0455248a76629ca9b604eca7dc5927cc593c5e9 \ + --hash=sha256:8ba470552b48e5835f1d23ecb936bb7f71d206f9dfeee64245f30c3270b994de \ + --hash=sha256:8c676b587da5673d3c75bd67dd2a8cdfeb282ca38a30f37950511766b26858c4 \ + --hash=sha256:8ec4a89295cd6cd4d1058a5e6aec6bf51e0eaaf9714774e1bfac7cfc9051db47 \ + --hash=sha256:94f3e1780abb45062287b4614a5bc0874519c86a777d4a7ad34978e86428b8dd \ + --hash=sha256:9a0f748eaa434a41fccf8e1ee7a3eed68af1b690e75328fd7a60af123c193b50 \ + --hash=sha256:a5629742881bcbc1f42e840af185fd4d83a5edeb96475a575f4da50d6ede337c \ + --hash=sha256:a65149d8ada1055029fcb665452b2814fe7d7082fcb0c5bed6db851cb69b2086 \ + --hash=sha256:b3c5ac4bed7519088103d9450a1107f76308ecf91d6dabc8a33a2fcfb18d0fba \ + --hash=sha256:b4fd7bd29610a83a8c9b564d457cf5bd92b4e11e79a4ee4716a63c959699b306 \ + --hash=sha256:bcd1fb5bb7b07f64c15618c89efcc2cfa3e95f0e3bcdbaf4642509de1942a699 \ + --hash=sha256:c12b5ae868897c7338519c03049a806af85b9b8c237b7d675b8c5e089e4a618e \ + --hash=sha256:c26845094b1af3c91852745ae78e3ea47abf3dbcd1cf962f16b9a5fbe3ee8488 \ + --hash=sha256:c6a660307ca9d4867caa8d9ca2c2658ab685de83792d1876274991adec7b93fa \ + --hash=sha256:c809a70e43c7977c4a42aefd62f0131823ebf7dd73556fa5d5950f5b354087e2 \ + --hash=sha256:c8b2351c85d855293a299038e1f89db92a2f35e8d2f783489c6f0b2b5f3fe8a3 \ + --hash=sha256:cb929ca942d0ec4fac404cbf520ee6cac37bf35be479b970c4ffadf2b6a1cad9 \ + --hash=sha256:d2c0a187a92a1cb5ef2c8ed5412dd8d4334272617f532d4ad4de31e0495bd923 \ + --hash=sha256:d69bfd8ec3219ae71bcde1f942b728903cad25fafe3100ba2258b973bd2bc1b2 \ + --hash=sha256:daffdf51ee5db69a82dd127eabecce20729e21f7a3680cf7cbb23f0829189790 \ + --hash=sha256:e58876c91f97b0952eb766123bfef372792ab3f4e3e1f1a2267834c2ab131734 \ + --hash=sha256:eda2616eb2313cbb3eebbe51f19362eb434b18e3bb599466a1ffa76a033fb916 \ + --hash=sha256:ee217c198f2e41f184f3869f3e485557296d505b5195c513b2bfe0062dc537f1 \ + --hash=sha256:f02541ef64077f22bf4924f225c0fd1248c168f86e4b7abdedd87d6ebaceab0f \ + --hash=sha256:f1b82c27e89fffc6da125d5eb0ca6e68017faf5efc078128cfaa42cf5cb38798 \ + --hash=sha256:fba162b8872d30fea8c52b258a542c5dfd7b235fb5cb352240c8d63b414013eb \ + --hash=sha256:fbbcb7b57dc9c794843e3d1258c0fbf0f48656d46ffe9e09b63bbd6e8cd5d0a2 \ + --hash=sha256:fcb4621042ac4b7865c179bb972ed0da0218a076dc1820ffc48b1d74c1e37fe9 psutil==5.9.8 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:02615ed8c5ea222323408ceba16c60e99c3f91639b07da6373fb7e6539abc56d \ --hash=sha256:05806de88103b25903dff19bb6692bd2e714ccf9e668d050d144012055cbca73 \ @@ -978,85 +865,80 @@ psutil==5.9.8 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:bd1184ceb3f87651a67b2708d4c3338e9b10c5df903f2e3776b62303b26cb631 \ --hash=sha256:d06016f7f8625a1825ba3732081d77c94589dca78b7a3fc072194851e88461a4 \ --hash=sha256:d16bbddf0693323b8c6123dd804100241da461e41d6e332fb0ba6058f630f8c8 -psycopg2-binary==2.9.9 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:03ef7df18daf2c4c07e2695e8cfd5ee7f748a1d54d802330985a78d2a5a6dca9 \ - --hash=sha256:0a602ea5aff39bb9fac6308e9c9d82b9a35c2bf288e184a816002c9fae930b77 \ - --hash=sha256:0c009475ee389757e6e34611d75f6e4f05f0cf5ebb76c6037508318e1a1e0d7e \ - --hash=sha256:0ef4854e82c09e84cc63084a9e4ccd6d9b154f1dbdd283efb92ecd0b5e2b8c84 \ - --hash=sha256:1236ed0952fbd919c100bc839eaa4a39ebc397ed1c08a97fc45fee2a595aa1b3 \ - --hash=sha256:143072318f793f53819048fdfe30c321890af0c3ec7cb1dfc9cc87aa88241de2 \ - --hash=sha256:15208be1c50b99203fe88d15695f22a5bed95ab3f84354c494bcb1d08557df67 \ - --hash=sha256:1873aade94b74715be2246321c8650cabf5a0d098a95bab81145ffffa4c13876 \ - --hash=sha256:18d0ef97766055fec15b5de2c06dd8e7654705ce3e5e5eed3b6651a1d2a9a152 \ - --hash=sha256:1ea665f8ce695bcc37a90ee52de7a7980be5161375d42a0b6c6abedbf0d81f0f \ - --hash=sha256:2293b001e319ab0d869d660a704942c9e2cce19745262a8aba2115ef41a0a42a \ - --hash=sha256:246b123cc54bb5361588acc54218c8c9fb73068bf227a4a531d8ed56fa3ca7d6 \ - --hash=sha256:275ff571376626195ab95a746e6a04c7df8ea34638b99fc11160de91f2fef503 \ - --hash=sha256:281309265596e388ef483250db3640e5f414168c5a67e9c665cafce9492eda2f \ - --hash=sha256:2d423c8d8a3c82d08fe8af900ad5b613ce3632a1249fd6a223941d0735fce493 \ - --hash=sha256:2e5afae772c00980525f6d6ecf7cbca55676296b580c0e6abb407f15f3706996 \ - --hash=sha256:30dcc86377618a4c8f3b72418df92e77be4254d8f89f14b8e8f57d6d43603c0f \ - --hash=sha256:31a34c508c003a4347d389a9e6fcc2307cc2150eb516462a7a17512130de109e \ - --hash=sha256:323ba25b92454adb36fa425dc5cf6f8f19f78948cbad2e7bc6cdf7b0d7982e59 \ - --hash=sha256:34eccd14566f8fe14b2b95bb13b11572f7c7d5c36da61caf414d23b91fcc5d94 \ - --hash=sha256:3a58c98a7e9c021f357348867f537017057c2ed7f77337fd914d0bedb35dace7 \ - --hash=sha256:3f78fd71c4f43a13d342be74ebbc0666fe1f555b8837eb113cb7416856c79682 \ - --hash=sha256:4154ad09dac630a0f13f37b583eae260c6aa885d67dfbccb5b02c33f31a6d420 \ - --hash=sha256:420f9bbf47a02616e8554e825208cb947969451978dceb77f95ad09c37791dae \ - --hash=sha256:4686818798f9194d03c9129a4d9a702d9e113a89cb03bffe08c6cf799e053291 \ - --hash=sha256:57fede879f08d23c85140a360c6a77709113efd1c993923c59fde17aa27599fe \ - --hash=sha256:60989127da422b74a04345096c10d416c2b41bd7bf2a380eb541059e4e999980 \ - --hash=sha256:64cf30263844fa208851ebb13b0732ce674d8ec6a0c86a4e160495d299ba3c93 \ - --hash=sha256:68fc1f1ba168724771e38bee37d940d2865cb0f562380a1fb1ffb428b75cb692 \ - --hash=sha256:6e6f98446430fdf41bd36d4faa6cb409f5140c1c2cf58ce0bbdaf16af7d3f119 \ - --hash=sha256:729177eaf0aefca0994ce4cffe96ad3c75e377c7b6f4efa59ebf003b6d398716 \ - --hash=sha256:72dffbd8b4194858d0941062a9766f8297e8868e1dd07a7b36212aaa90f49472 \ - --hash=sha256:75723c3c0fbbf34350b46a3199eb50638ab22a0228f93fb472ef4d9becc2382b \ - --hash=sha256:77853062a2c45be16fd6b8d6de2a99278ee1d985a7bd8b103e97e41c034006d2 \ - --hash=sha256:78151aa3ec21dccd5cdef6c74c3e73386dcdfaf19bced944169697d7ac7482fc \ - --hash=sha256:7f01846810177d829c7692f1f5ada8096762d9172af1b1a28d4ab5b77c923c1c \ - --hash=sha256:804d99b24ad523a1fe18cc707bf741670332f7c7412e9d49cb5eab67e886b9b5 \ - --hash=sha256:81ff62668af011f9a48787564ab7eded4e9fb17a4a6a74af5ffa6a457400d2ab \ - --hash=sha256:8359bf4791968c5a78c56103702000105501adb557f3cf772b2c207284273984 \ - --hash=sha256:83791a65b51ad6ee6cf0845634859d69a038ea9b03d7b26e703f94c7e93dbcf9 \ - --hash=sha256:8532fd6e6e2dc57bcb3bc90b079c60de896d2128c5d9d6f24a63875a95a088cf \ - --hash=sha256:876801744b0dee379e4e3c38b76fc89f88834bb15bf92ee07d94acd06ec890a0 \ - --hash=sha256:8dbf6d1bc73f1d04ec1734bae3b4fb0ee3cb2a493d35ede9badbeb901fb40f6f \ - --hash=sha256:8f8544b092a29a6ddd72f3556a9fcf249ec412e10ad28be6a0c0d948924f2212 \ - --hash=sha256:911dda9c487075abd54e644ccdf5e5c16773470a6a5d3826fda76699410066fb \ - --hash=sha256:977646e05232579d2e7b9c59e21dbe5261f403a88417f6a6512e70d3f8a046be \ - --hash=sha256:9dba73be7305b399924709b91682299794887cbbd88e38226ed9f6712eabee90 \ - --hash=sha256:a148c5d507bb9b4f2030a2025c545fccb0e1ef317393eaba42e7eabd28eb6041 \ - --hash=sha256:a6cdcc3ede532f4a4b96000b6362099591ab4a3e913d70bcbac2b56c872446f7 \ - --hash=sha256:ac05fb791acf5e1a3e39402641827780fe44d27e72567a000412c648a85ba860 \ - --hash=sha256:b0605eaed3eb239e87df0d5e3c6489daae3f7388d455d0c0b4df899519c6a38d \ - --hash=sha256:b58b4710c7f4161b5e9dcbe73bb7c62d65670a87df7bcce9e1faaad43e715245 \ - --hash=sha256:b6356793b84728d9d50ead16ab43c187673831e9d4019013f1402c41b1db9b27 \ - --hash=sha256:b76bedd166805480ab069612119ea636f5ab8f8771e640ae103e05a4aae3e417 \ - --hash=sha256:bc7bb56d04601d443f24094e9e31ae6deec9ccb23581f75343feebaf30423359 \ - --hash=sha256:c2470da5418b76232f02a2fcd2229537bb2d5a7096674ce61859c3229f2eb202 \ - --hash=sha256:c332c8d69fb64979ebf76613c66b985414927a40f8defa16cf1bc028b7b0a7b0 \ - --hash=sha256:c6af2a6d4b7ee9615cbb162b0738f6e1fd1f5c3eda7e5da17861eacf4c717ea7 \ - --hash=sha256:c77e3d1862452565875eb31bdb45ac62502feabbd53429fdc39a1cc341d681ba \ - --hash=sha256:ca08decd2697fdea0aea364b370b1249d47336aec935f87b8bbfd7da5b2ee9c1 \ - --hash=sha256:ca49a8119c6cbd77375ae303b0cfd8c11f011abbbd64601167ecca18a87e7cdd \ - --hash=sha256:cb16c65dcb648d0a43a2521f2f0a2300f40639f6f8c1ecbc662141e4e3e1ee07 \ - --hash=sha256:d2997c458c690ec2bc6b0b7ecbafd02b029b7b4283078d3b32a852a7ce3ddd98 \ - --hash=sha256:d3f82c171b4ccd83bbaf35aa05e44e690113bd4f3b7b6cc54d2219b132f3ae55 \ - --hash=sha256:dc4926288b2a3e9fd7b50dc6a1909a13bbdadfc67d93f3374d984e56f885579d \ - --hash=sha256:ead20f7913a9c1e894aebe47cccf9dc834e1618b7aa96155d2091a626e59c972 \ - --hash=sha256:ebdc36bea43063116f0486869652cb2ed7032dbc59fbcb4445c4862b5c1ecf7f \ - --hash=sha256:ed1184ab8f113e8d660ce49a56390ca181f2981066acc27cf637d5c1e10ce46e \ - --hash=sha256:ee825e70b1a209475622f7f7b776785bd68f34af6e7a46e2e42f27b659b5bc26 \ - --hash=sha256:f7ae5d65ccfbebdfa761585228eb4d0df3a8b15cfb53bd953e713e09fbb12957 \ - --hash=sha256:f7fc5a5acafb7d6ccca13bfa8c90f8c51f13d8fb87d95656d3950f0158d3ce53 \ - --hash=sha256:f9b5571d33660d5009a8b3c25dc1db560206e2d2f89d3df1cb32d72c0d117d52 -pyasn1-modules==0.3.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:5bd01446b736eb9d31512a30d46c1ac3395d676c6f3cafa4c03eb54b9925631c \ - --hash=sha256:d3ccd6ed470d9ffbc716be08bd90efbd44d0734bc9303818f7336070984a162d -pyasn1==0.5.1 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:4439847c58d40b1d0a573d07e3856e95333f1976294494c325775aeca506eb58 \ - --hash=sha256:6d391a96e59b23130a5cfa74d6fd7f388dbbe26cc8f1edf39fdddf08d9d6676c +psycopg2-binary==2.9.10 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:04392983d0bb89a8717772a193cfaac58871321e3ec69514e1c4e0d4957b5aff \ + --hash=sha256:056470c3dc57904bbf63d6f534988bafc4e970ffd50f6271fc4ee7daad9498a5 \ + --hash=sha256:0ea8e3d0ae83564f2fc554955d327fa081d065c8ca5cc6d2abb643e2c9c1200f \ + --hash=sha256:155e69561d54d02b3c3209545fb08938e27889ff5a10c19de8d23eb5a41be8a5 \ + --hash=sha256:18c5ee682b9c6dd3696dad6e54cc7ff3a1a9020df6a5c0f861ef8bfd338c3ca0 \ + --hash=sha256:19721ac03892001ee8fdd11507e6a2e01f4e37014def96379411ca99d78aeb2c \ + --hash=sha256:1a6784f0ce3fec4edc64e985865c17778514325074adf5ad8f80636cd029ef7c \ + --hash=sha256:2286791ececda3a723d1910441c793be44625d86d1a4e79942751197f4d30341 \ + --hash=sha256:230eeae2d71594103cd5b93fd29d1ace6420d0b86f4778739cb1a5a32f607d1f \ + --hash=sha256:245159e7ab20a71d989da00f280ca57da7641fa2cdcf71749c193cea540a74f7 \ + --hash=sha256:26540d4a9a4e2b096f1ff9cce51253d0504dca5a85872c7f7be23be5a53eb18d \ + --hash=sha256:270934a475a0e4b6925b5f804e3809dd5f90f8613621d062848dd82f9cd62007 \ + --hash=sha256:2ad26b467a405c798aaa1458ba09d7e2b6e5f96b1ce0ac15d82fd9f95dc38a92 \ + --hash=sha256:2b3d2491d4d78b6b14f76881905c7a8a8abcf974aad4a8a0b065273a0ed7a2cb \ + --hash=sha256:2ce3e21dc3437b1d960521eca599d57408a695a0d3c26797ea0f72e834c7ffe5 \ + --hash=sha256:30e34c4e97964805f715206c7b789d54a78b70f3ff19fbe590104b71c45600e5 \ + --hash=sha256:3216ccf953b3f267691c90c6fe742e45d890d8272326b4a8b20850a03d05b7b8 \ + --hash=sha256:32581b3020c72d7a421009ee1c6bf4a131ef5f0a968fab2e2de0c9d2bb4577f1 \ + --hash=sha256:35958ec9e46432d9076286dda67942ed6d968b9c3a6a2fd62b48939d1d78bf68 \ + --hash=sha256:3abb691ff9e57d4a93355f60d4f4c1dd2d68326c968e7db17ea96df3c023ef73 \ + --hash=sha256:3c18f74eb4386bf35e92ab2354a12c17e5eb4d9798e4c0ad3a00783eae7cd9f1 \ + --hash=sha256:3c4745a90b78e51d9ba06e2088a2fe0c693ae19cc8cb051ccda44e8df8a6eb53 \ + --hash=sha256:3c4ded1a24b20021ebe677b7b08ad10bf09aac197d6943bfe6fec70ac4e4690d \ + --hash=sha256:3e9c76f0ac6f92ecfc79516a8034a544926430f7b080ec5a0537bca389ee0906 \ + --hash=sha256:48b338f08d93e7be4ab2b5f1dbe69dc5e9ef07170fe1f86514422076d9c010d0 \ + --hash=sha256:4b3df0e6990aa98acda57d983942eff13d824135fe2250e6522edaa782a06de2 \ + --hash=sha256:512d29bb12608891e349af6a0cccedce51677725a921c07dba6342beaf576f9a \ + --hash=sha256:5a507320c58903967ef7384355a4da7ff3f28132d679aeb23572753cbf2ec10b \ + --hash=sha256:5c370b1e4975df846b0277b4deba86419ca77dbc25047f535b0bb03d1a544d44 \ + --hash=sha256:6b269105e59ac96aba877c1707c600ae55711d9dcd3fc4b5012e4af68e30c648 \ + --hash=sha256:6d4fa1079cab9018f4d0bd2db307beaa612b0d13ba73b5c6304b9fe2fb441ff7 \ + --hash=sha256:6dc08420625b5a20b53551c50deae6e231e6371194fa0651dbe0fb206452ae1f \ + --hash=sha256:73aa0e31fa4bb82578f3a6c74a73c273367727de397a7a0f07bd83cbea696baa \ + --hash=sha256:7559bce4b505762d737172556a4e6ea8a9998ecac1e39b5233465093e8cee697 \ + --hash=sha256:79625966e176dc97ddabc142351e0409e28acf4660b88d1cf6adb876d20c490d \ + --hash=sha256:7a813c8bdbaaaab1f078014b9b0b13f5de757e2b5d9be6403639b298a04d218b \ + --hash=sha256:7b2c956c028ea5de47ff3a8d6b3cc3330ab45cf0b7c3da35a2d6ff8420896526 \ + --hash=sha256:7f4152f8f76d2023aac16285576a9ecd2b11a9895373a1f10fd9db54b3ff06b4 \ + --hash=sha256:7f5d859928e635fa3ce3477704acee0f667b3a3d3e4bb109f2b18d4005f38287 \ + --hash=sha256:851485a42dbb0bdc1edcdabdb8557c09c9655dfa2ca0460ff210522e073e319e \ + --hash=sha256:8608c078134f0b3cbd9f89b34bd60a943b23fd33cc5f065e8d5f840061bd0673 \ + --hash=sha256:880845dfe1f85d9d5f7c412efea7a08946a46894537e4e5d091732eb1d34d9a0 \ + --hash=sha256:8aabf1c1a04584c168984ac678a668094d831f152859d06e055288fa515e4d30 \ + --hash=sha256:8aecc5e80c63f7459a1a2ab2c64df952051df196294d9f739933a9f6687e86b3 \ + --hash=sha256:8cd9b4f2cfab88ed4a9106192de509464b75a906462fb846b936eabe45c2063e \ + --hash=sha256:8de718c0e1c4b982a54b41779667242bc630b2197948405b7bd8ce16bcecac92 \ + --hash=sha256:9440fa522a79356aaa482aa4ba500b65f28e5d0e63b801abf6aa152a29bd842a \ + --hash=sha256:b5f86c56eeb91dc3135b3fd8a95dc7ae14c538a2f3ad77a19645cf55bab1799c \ + --hash=sha256:b73d6d7f0ccdad7bc43e6d34273f70d587ef62f824d7261c4ae9b8b1b6af90e8 \ + --hash=sha256:bb89f0a835bcfc1d42ccd5f41f04870c1b936d8507c6df12b7737febc40f0909 \ + --hash=sha256:c3cc28a6fd5a4a26224007712e79b81dbaee2ffb90ff406256158ec4d7b52b47 \ + --hash=sha256:ce5ab4bf46a211a8e924d307c1b1fcda82368586a19d0a24f8ae166f5c784864 \ + --hash=sha256:d00924255d7fc916ef66e4bf22f354a940c67179ad3fd7067d7a0a9c84d2fbfc \ + --hash=sha256:d7cd730dfa7c36dbe8724426bf5612798734bff2d3c3857f36f2733f5bfc7c00 \ + --hash=sha256:e217ce4d37667df0bc1c397fdcd8de5e81018ef305aed9415c3b093faaeb10fb \ + --hash=sha256:e3923c1d9870c49a2d44f795df0c889a22380d36ef92440ff618ec315757e539 \ + --hash=sha256:e5720a5d25e3b99cd0dc5c8a440570469ff82659bb09431c1439b92caf184d3b \ + --hash=sha256:e8b58f0a96e7a1e341fc894f62c1177a7c83febebb5ff9123b579418fdc8a481 \ + --hash=sha256:e984839e75e0b60cfe75e351db53d6db750b00de45644c5d1f7ee5d1f34a1ce5 \ + --hash=sha256:eb09aa7f9cecb45027683bb55aebaaf45a0df8bf6de68801a6afdc7947bb09d4 \ + --hash=sha256:ec8a77f521a17506a24a5f626cb2aee7850f9b69a0afe704586f63a464f3cd64 \ + --hash=sha256:ecced182e935529727401b24d76634a357c71c9275b356efafd8a2a91ec07392 \ + --hash=sha256:ee0e8c683a7ff25d23b55b11161c2663d4b099770f6085ff0a20d4505778d6b4 \ + --hash=sha256:f0c2d907a1e102526dd2986df638343388b94c33860ff3bbe1384130828714b1 \ + --hash=sha256:f758ed67cab30b9a8d2833609513ce4d3bd027641673d4ebc9c067e4d208eec1 \ + --hash=sha256:f8157bed2f51db683f31306aa497311b560f2265998122abe1dce6428bd86567 \ + --hash=sha256:ffe8ed017e4ed70f68b7b371d84b7d4a790368db9203dfc2d222febd3a9c8863 +pyasn1-modules==0.4.1 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:49bfa96b45a292b711e986f222502c1c9a5e1f4e568fc30e2574a6c7d07838fd \ + --hash=sha256:c28e2dbf9c06ad61c71a075c7e0f9fd0f1b0bb2d2ad4377f240d33ac2ab60a7c +pyasn1==0.6.1 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:0d632f46f2ba09143da3a8afe9e33fb6f92fa2320ab7e886e2d0f7672af84629 \ + --hash=sha256:6f580d2bdd84365380830acf45550f2511469f673cb4a5ae3857a3170128b034 pycparser==2.22 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6 \ --hash=sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc @@ -1093,39 +975,39 @@ pycryptodome==3.21.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:f35e442630bc4bc2e1878482d6f59ea22e280d7121d7adeaedba58c23ab6386b \ --hash=sha256:f7787e0d469bdae763b876174cf2e6c0f7be79808af26b1da96f1a64bcf47297 \ --hash=sha256:ff99f952db3db2fbe98a0b355175f93ec334ba3d01bbde25ad3a5a33abc02b58 -pycryptodomex==3.20.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:0daad007b685db36d977f9de73f61f8da2a7104e20aca3effd30752fd56f73e1 \ - --hash=sha256:108e5f1c1cd70ffce0b68739c75734437c919d2eaec8e85bffc2c8b4d2794305 \ - --hash=sha256:19764605feea0df966445d46533729b645033f134baeb3ea26ad518c9fdf212c \ - --hash=sha256:1be97461c439a6af4fe1cf8bf6ca5936d3db252737d2f379cc6b2e394e12a458 \ - --hash=sha256:25cd61e846aaab76d5791d006497134602a9e451e954833018161befc3b5b9ed \ - --hash=sha256:2a47bcc478741b71273b917232f521fd5704ab4b25d301669879e7273d3586cc \ - --hash=sha256:59af01efb011b0e8b686ba7758d59cf4a8263f9ad35911bfe3f416cee4f5c08c \ - --hash=sha256:5dcac11031a71348faaed1f403a0debd56bf5404232284cf8c761ff918886ebc \ - --hash=sha256:62a5ec91388984909bb5398ea49ee61b68ecb579123694bffa172c3b0a107079 \ - --hash=sha256:645bd4ca6f543685d643dadf6a856cc382b654cc923460e3a10a49c1b3832aeb \ - --hash=sha256:653b29b0819605fe0898829c8ad6400a6ccde096146730c2da54eede9b7b8baa \ - --hash=sha256:69138068268127cd605e03438312d8f271135a33140e2742b417d027a0539427 \ - --hash=sha256:6e186342cfcc3aafaad565cbd496060e5a614b441cacc3995ef0091115c1f6c5 \ - --hash=sha256:76bd15bb65c14900d98835fcd10f59e5e0435077431d3a394b60b15864fddd64 \ - --hash=sha256:7805830e0c56d88f4d491fa5ac640dfc894c5ec570d1ece6ed1546e9df2e98d6 \ - --hash=sha256:7a710b79baddd65b806402e14766c721aee8fb83381769c27920f26476276c1e \ - --hash=sha256:7a7a8f33a1f1fb762ede6cc9cbab8f2a9ba13b196bfaf7bc6f0b39d2ba315a43 \ - --hash=sha256:82ee7696ed8eb9a82c7037f32ba9b7c59e51dda6f105b39f043b6ef293989cb3 \ - --hash=sha256:88afd7a3af7ddddd42c2deda43d53d3dfc016c11327d0915f90ca34ebda91499 \ - --hash=sha256:8af1a451ff9e123d0d8bd5d5e60f8e3315c3a64f3cdd6bc853e26090e195cdc8 \ - --hash=sha256:8ee606964553c1a0bc74057dd8782a37d1c2bc0f01b83193b6f8bb14523b877b \ - --hash=sha256:91852d4480a4537d169c29a9d104dda44094c78f1f5b67bca76c29a91042b623 \ - --hash=sha256:9c682436c359b5ada67e882fec34689726a09c461efd75b6ea77b2403d5665b7 \ - --hash=sha256:bc3ee1b4d97081260d92ae813a83de4d2653206967c4a0a017580f8b9548ddbc \ - --hash=sha256:bca649483d5ed251d06daf25957f802e44e6bb6df2e8f218ae71968ff8f8edc4 \ - --hash=sha256:c39778fd0548d78917b61f03c1fa8bfda6cfcf98c767decf360945fe6f97461e \ - --hash=sha256:cbe71b6712429650e3883dc81286edb94c328ffcd24849accac0a4dbcc76958a \ - --hash=sha256:d00fe8596e1cc46b44bf3907354e9377aa030ec4cd04afbbf6e899fc1e2a7781 \ - --hash=sha256:d3584623e68a5064a04748fb6d76117a21a7cb5eaba20608a41c7d0c61721794 \ - --hash=sha256:e48217c7901edd95f9f097feaa0388da215ed14ce2ece803d3f300b4e694abea \ - --hash=sha256:f2e497413560e03421484189a6b65e33fe800d3bd75590e6d78d4dfdb7accf3b \ - --hash=sha256:ff5c9a67f8a4fba4aed887216e32cbc48f2a6fb2673bb10a99e43be463e15913 +pycryptodomex==3.21.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:0df2608682db8279a9ebbaf05a72f62a321433522ed0e499bc486a6889b96bf3 \ + --hash=sha256:103c133d6cd832ae7266feb0a65b69e3a5e4dbbd6f3a3ae3211a557fd653f516 \ + --hash=sha256:1233443f19d278c72c4daae749872a4af3787a813e05c3561c73ab0c153c7b0f \ + --hash=sha256:222d0bd05381dd25c32dd6065c071ebf084212ab79bab4599ba9e6a3e0009e6c \ + --hash=sha256:27e84eeff24250ffec32722334749ac2a57a5fd60332cd6a0680090e7c42877e \ + --hash=sha256:34325b84c8b380675fd2320d0649cdcbc9cf1e0d1526edbe8fce43ed858cdc7e \ + --hash=sha256:365aa5a66d52fd1f9e0530ea97f392c48c409c2f01ff8b9a39c73ed6f527d36c \ + --hash=sha256:3efddfc50ac0ca143364042324046800c126a1d63816d532f2e19e6f2d8c0c31 \ + --hash=sha256:46eb1f0c8d309da63a2064c28de54e5e614ad17b7e2f88df0faef58ce192fc7b \ + --hash=sha256:5241bdb53bcf32a9568770a6584774b1b8109342bd033398e4ff2da052123832 \ + --hash=sha256:52e23a0a6e61691134aa8c8beba89de420602541afaae70f66e16060fdcd677e \ + --hash=sha256:56435c7124dd0ce0c8bdd99c52e5d183a0ca7fdcd06c5d5509423843f487dd0b \ + --hash=sha256:5823d03e904ea3e53aebd6799d6b8ec63b7675b5d2f4a4bd5e3adcb512d03b37 \ + --hash=sha256:65d275e3f866cf6fe891411be9c1454fb58809ccc5de6d3770654c47197acd65 \ + --hash=sha256:770d630a5c46605ec83393feaa73a9635a60e55b112e1fb0c3cea84c2897aa0a \ + --hash=sha256:77ac2ea80bcb4b4e1c6a596734c775a1615d23e31794967416afc14852a639d3 \ + --hash=sha256:7a1058e6dfe827f4209c5cae466e67610bcd0d66f2f037465daa2a29d92d952b \ + --hash=sha256:8a9d8342cf22b74a746e3c6c9453cb0cfbb55943410e3a2619bd9164b48dc9d9 \ + --hash=sha256:8ef436cdeea794015263853311f84c1ff0341b98fc7908e8a70595a68cefd971 \ + --hash=sha256:9aa0cf13a1a1128b3e964dc667e5fe5c6235f7d7cfb0277213f0e2a783837cc2 \ + --hash=sha256:9ba09a5b407cbb3bcb325221e346a140605714b5e880741dc9a1e9ecf1688d42 \ + --hash=sha256:a192fb46c95489beba9c3f002ed7d93979423d1b2a53eab8771dbb1339eb3ddd \ + --hash=sha256:a3d77919e6ff56d89aada1bd009b727b874d464cb0e2e3f00a49f7d2e709d76e \ + --hash=sha256:b0e9765f93fe4890f39875e6c90c96cb341767833cfa767f41b490b506fa9ec0 \ + --hash=sha256:bbb07f88e277162b8bfca7134b34f18b400d84eac7375ce73117f865e3c80d4c \ + --hash=sha256:c07e64867a54f7e93186a55bec08a18b7302e7bee1b02fd84c6089ec215e723a \ + --hash=sha256:cc7e111e66c274b0df5f4efa679eb31e23c7545d702333dfd2df10ab02c2a2ce \ + --hash=sha256:da76ebf6650323eae7236b54b1b1f0e57c16483be6e3c1ebf901d4ada47563b6 \ + --hash=sha256:dbeb84a399373df84a69e0919c1d733b89e049752426041deeb30d68e9867822 \ + --hash=sha256:e859e53d983b7fe18cb8f1b0e29d991a5c93be2c8dd25db7db1fe3bd3617f6f9 \ + --hash=sha256:ef046b2e6c425647971b51424f0f88d8a2e0a2a63d3531817968c42078895c00 \ + --hash=sha256:feaecdce4e5c0045e7a287de0c4351284391fe170729aa9182f6bd967631b3a8 pydantic-core==2.23.4 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:0a7df63886be5e270da67e0966cf4afbae86069501d35c8c1b3b6c168f42cb36 \ --hash=sha256:0cb3da3fd1b6a5d0279a01877713dbda118a2a4fc6f0d821a57da2e464793f05 \ @@ -1235,81 +1117,75 @@ pydeep2==0.5.1 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:e14b310b820d895a7354be7fd025de874892df249cbfb3ad8a524459e1511fd8 \ --hash=sha256:ef00ca5681a2c4ad5dc744db5f8ae5406d3f13121b38d84cc58dfb8fce4c3dc2 \ --hash=sha256:f248e3161deb53d46a9368a7c164e36d83004faf2f11625d47a5cf23a6bdd2cb -pyelftools==0.31 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:c774416b10310156879443b81187d182d8d9ee499660380e645918b50bc88f99 \ - --hash=sha256:f52de7b3c7e8c64c8abc04a79a1cf37ac5fb0b8a49809827130b858944840607 pygal==2.4.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:27abab93cbc31e21f3c6bdecc05bda6cd3570cbdbd8297b7caa6904051b50d72 \ --hash=sha256:9204f05380b02a8a32f9bf99d310b51aa2a932cba5b369f7a4dc3705f0a4ce83 -pygments==2.18.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:786ff802f32e91311bff3889f6e9a86e81505fe99f2735bb6d60ae0c5004f199 \ - --hash=sha256:b8e6aca0523f3ab76fee51799c488e38782ac06eafcf95e7ba832985c8e7b13a pyguacamole==0.11 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:7f8d8652ce2e86473d72a50e0c9d8a8e0c3c74e373c6b926ca4c851774cae608 \ --hash=sha256:d6facde097a1b1a3048b20fb2ff88b024744ceb2865fb912525da7ebb7779695 pyjwt[crypto]==2.9.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:3b02fb0f44517787776cf48f2ae25d8e14f300e6d7545a4315cee571a415e850 \ --hash=sha256:7e1e5b56cc735432a7369cbfa0efe50fa113ebecdc04ae6922deba8b84582d0c -pymongo==4.9.1 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:0492ef43f3342354cf581712e431621c221f60c877ebded84e3f3e53b71bbbe0 \ - --hash=sha256:08fbab69f3fb6f8088c81f4c4a8abd84a99c132034f5e27e47f894bbcb6bf439 \ - --hash=sha256:16d2efe559d0d96bc0b74b3ff76701ad6f6e1a65f6581b573dcacc29158131c8 \ - --hash=sha256:172d8ba0f567e351a18765db23dab7dbcfdffd91a8788d90d46b350f80a40781 \ - --hash=sha256:1b4b961fce213f2bcdc92268f85111a3668c61b9b4d4e7ece27dce3a137cfcbd \ - --hash=sha256:1d79f20f9c7cbc1c708fb80b648b6fbd3220fd3437a9bd6017c1eb592e03b361 \ - --hash=sha256:1d7aa9cc2d92e73bdb036c578ba019da94ea165eb147e691cd910a6fab7ce3b7 \ - --hash=sha256:1dfd2aa30174d36a3ef1dae4ee4c89710c2d65cac52ce6e13f17c710edbd61cf \ - --hash=sha256:1fac1def9e9073f1c80198c99f0ec39c2528236c8912d96d7fd3b0237f4c523a \ - --hash=sha256:286fb275267f0293364ba579f6354452599161f1902ad411061c7f744ab88328 \ - --hash=sha256:34e4993ae78be56f9e27a141168a1ab78253576fa3e893fa335a719ce204c3ef \ - --hash=sha256:375765ec81b1f0a26d08928afea0c3dff897c36080a090be53fc7b70cc51d497 \ - --hash=sha256:3a846423c4535428f69a90a1451df3718bc59f0c4ab685b9e96d3071951e0be4 \ - --hash=sha256:42c19d2b094cdd0ead7dbb38860bbe8268c140334ce55d8b39204ddb4ebd4904 \ - --hash=sha256:4327c0d9bd616b8289691360f2d4a09a72fe35479795832eae0d4ff78af53923 \ - --hash=sha256:432ad395d2233056b042ccc73234e7136aa65d944d6bd8b5138394bd38aaff79 \ - --hash=sha256:47b4896544095d172c366dd4d4ea1da6b0ab1a77d8416897cc1801e2421b1e67 \ - --hash=sha256:4cddb51cead9700c4dccc916952bc0321b8d766bf782d374bfa0e93ef47c1d20 \ - --hash=sha256:4d1b959a3dda0775d9111622ee47ad47772aed3a9da2e7d5f2f513fa68175dea \ - --hash=sha256:51dbc6251c6783dfcc7d657c346986d8bad7210989b2fe15de16db5204a8e7ae \ - --hash=sha256:56877cfcdf7dfc5c6408e4551ec0d6d65ebbca4d744a0bc90400f09ef6bbcc8a \ - --hash=sha256:679b8d55854da7c7fdb82aa5e092ab4de0144daf6758defed8ab00ff9ce05360 \ - --hash=sha256:687cf70e096381bc65b4273a6a9319617618f7ace65caffc356e1099c4a68511 \ - --hash=sha256:6bb3d5282278594753089dc7da48bfae4a7f337a2dd4d397eabb591c649e58d0 \ - --hash=sha256:75d5974f874acdb2f125bdbe785045b23a39ecce1d3143dd5712800c7b6d25eb \ - --hash=sha256:7f962d74201c772555f7a78792fed820a5ea76db5c7ee6cf43748e411b44e430 \ - --hash=sha256:8089003a99127f917bdbeec177d41cef019cda8ec70534c1018cb60aacd23c2a \ - --hash=sha256:8b632e01617f2608880f7b9926f54a5f5ebb51631996e0540fff7fc7980663c9 \ - --hash=sha256:8f0d5258bc85a4e6b5bcae8160628168e71ec4625a58ceb53327c3280a0b6914 \ - --hash=sha256:91b1a92214c3912af5467f77c2f6435cd76f6de64c70cba7bb4ee43eba7f459e \ - --hash=sha256:95418e334629440f70fe5ceeefc6cbbd50defb566901c8d68179ffbaec8d5f01 \ - --hash=sha256:96462fb2175f740701d229f52018ea6e4adc4148c4112e6628bb359dd534a3df \ - --hash=sha256:99b611ff75b5d9e17183dcf9584a7b04f9db07e51a162f23ea05e485e0735c0a \ - --hash=sha256:9d78adf25967c06298c7e488f4cfab79a390fc32c2b1d428613976f99031603d \ - --hash=sha256:9fbe9fad27619ac4cfda5df0ade26a99906da7dfe7b01deddc25997eb1804e4c \ - --hash=sha256:a0b10cf51ec14a487c94709d294c00e1fb6a0a4c38cdc3acfb2ced5ef60972a0 \ - --hash=sha256:a2b12c74cfd90147babb77f9728646bcedfdbd2bd2a5b4130a00e3a0af1a3d34 \ - --hash=sha256:a40ea8bc9cffb61c5c9c426c430d22235e085e610ee81ae075ddf51f12f76236 \ - --hash=sha256:a7689da1d1b444284e4ea9ab2eb64a15307b6b795918c0f3cd7774dd1d8a7556 \ - --hash=sha256:aa4493f304b33c5d2ecee3055c98889ac6724d56f5f922d47420a45d0d4099c9 \ - --hash=sha256:b23211c031b45d0f32de83ab7d77f9c26f1025c2d2c91463a5d8594a16103655 \ - --hash=sha256:b347052d510989d1f52b8553b31297f21cf74bd9f6aed71ee84e563492f4ff17 \ - --hash=sha256:b4c793db8457c856f333f396798470b9bfe405e17c307d581532c74cec70150c \ - --hash=sha256:b7f2d34390acf60e229c30037d1473fcf69f4536cd7f48f6f78c0c931c61c505 \ - --hash=sha256:c4204fad54830a3173a5c939cd052d0561fba03dba7e0ff6852fd631f3314aa4 \ - --hash=sha256:d476d91a5c9e6c37bc8ec3fb294e1c01d95736ccf01a59bb1540fe2f710f826e \ - --hash=sha256:db5b299e11284f8d82ce2983d8e19fcc28f98f902a179709ef1982b4cca6f8b8 \ - --hash=sha256:dc3d070d746ab79e9b393a5c236df20e56607389af2b79bf1bfe9a841117558e \ - --hash=sha256:dd3352eaf578f8e9bdea7a5692910eedad1e8680f60726fc70e99c8af51a5449 \ - --hash=sha256:e02b03e3815b80a63e773e4c32aed3cf5633d406f376477be74550295c211256 \ - --hash=sha256:e1f346811d4a2369f88ab7a6f886fa9c3bbc9ed4e4f4a3becca8717a73d465cb \ - --hash=sha256:e3645aff8419ca60f9ccd08966b2f6b0d78053f9f98a814d025426f1d874c19a \ - --hash=sha256:ea3f0196e7c311b9944a609ac175bd91ab97952164a1246716fdd38d53ca3bcc \ - --hash=sha256:f05e34d401be871d7c87cb10727d49315444e4ded07ff876a595e4c23b7436da \ - --hash=sha256:f23a046531030318622414f21198e232cf93c5640da9a80b45596a059c8cc090 \ - --hash=sha256:f838f613e74b4dad8ace0d90f42346005bece4eda5bf6d389cfadb8322d39316 \ - --hash=sha256:f8e8b8deba6a4bff3dd5421071083219521c74d2acae0322de5c06f1a66c56af \ - --hash=sha256:fbb1c7dfcf6c44e9e1928290631c7603817991cdf570691c9e15fca594918435 \ - --hash=sha256:fe709d05654c12fc513617c8d5c8d05b7e9cf1d5d94ada68add4e89530c867d2 +pymongo==4.10.1 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:0783e0c8e95397c84e9cf8ab092ab1e5dd7c769aec0ef3a5838ae7173b98dea0 \ + --hash=sha256:0f56707497323150bd2ed5d63067f4ffce940d0549d4ea2dfae180deec7f9363 \ + --hash=sha256:11280809e5dacaef4971113f0b4ff4696ee94cfdb720019ff4fa4f9635138252 \ + --hash=sha256:15a624d752dd3c89d10deb0ef6431559b6d074703cab90a70bb849ece02adc6b \ + --hash=sha256:15b1492cc5c7cd260229590be7218261e81684b8da6d6de2660cf743445500ce \ + --hash=sha256:1a970fd3117ab40a4001c3dad333bbf3c43687d90f35287a6237149b5ccae61d \ + --hash=sha256:1ec3fa88b541e0481aff3c35194c9fac96e4d57ec5d1c122376000eb28c01431 \ + --hash=sha256:1ecc2455e3974a6c429687b395a0bc59636f2d6aedf5785098cf4e1f180f1c71 \ + --hash=sha256:23e1d62df5592518204943b507be7b457fb8a4ad95a349440406fd42db5d0923 \ + --hash=sha256:29e1c323c28a4584b7095378ff046815e39ff82cdb8dc4cc6dfe3acf6f9ad1f8 \ + --hash=sha256:2e3a593333e20c87415420a4fb76c00b7aae49b6361d2e2205b6fece0563bf40 \ + --hash=sha256:345f8d340802ebce509f49d5833cc913da40c82f2e0daf9f60149cacc9ca680f \ + --hash=sha256:3a70d5efdc0387ac8cd50f9a5f379648ecfc322d14ec9e1ba8ec957e5d08c372 \ + --hash=sha256:409ab7d6c4223e5c85881697f365239dd3ed1b58f28e4124b846d9d488c86880 \ + --hash=sha256:442ca247f53ad24870a01e80a71cd81b3f2318655fd9d66748ee2bd1b1569d9e \ + --hash=sha256:45ee87a4e12337353242bc758accc7fb47a2f2d9ecc0382a61e64c8f01e86708 \ + --hash=sha256:4924355245a9c79f77b5cda2db36e0f75ece5faf9f84d16014c0a297f6d66786 \ + --hash=sha256:544890085d9641f271d4f7a47684450ed4a7344d6b72d5968bfae32203b1bb7c \ + --hash=sha256:57ee6becae534e6d47848c97f6a6dff69e3cce7c70648d6049bd586764febe59 \ + --hash=sha256:594dd721b81f301f33e843453638e02d92f63c198358e5a0fa8b8d0b1218dabc \ + --hash=sha256:5ded27a4a5374dae03a92e084a60cdbcecd595306555bda553b833baf3fc4868 \ + --hash=sha256:6131bc6568b26e7495a9f3ef2b1700566b76bbecd919f4472bfe90038a61f425 \ + --hash=sha256:6f437a612f4d4f7aca1812311b1e84477145e950fdafe3285b687ab8c52541f3 \ + --hash=sha256:6fb6a72e88df46d1c1040fd32cd2d2c5e58722e5d3e31060a0393f04ad3283de \ + --hash=sha256:70645abc714f06b4ad6b72d5bf73792eaad14e3a2cfe29c62a9c81ada69d9e4b \ + --hash=sha256:72e2ace7456167c71cfeca7dcb47bd5dceda7db2231265b80fc625c5e8073186 \ + --hash=sha256:778ac646ce6ac1e469664062dfe9ae1f5c9961f7790682809f5ec3b8fda29d65 \ + --hash=sha256:7bd26b2aec8ceeb95a5d948d5cc0f62b0eb6d66f3f4230705c1e3d3d2c04ec76 \ + --hash=sha256:7c4d0e7cd08ef9f8fbf2d15ba281ed55604368a32752e476250724c3ce36c72e \ + --hash=sha256:88dc4aa45f8744ccfb45164aedb9a4179c93567bbd98a33109d7dc400b00eb08 \ + --hash=sha256:8ad05eb9c97e4f589ed9e74a00fcaac0d443ccd14f38d1258eb4c39a35dd722b \ + --hash=sha256:90bc6912948dfc8c363f4ead54d54a02a15a7fee6cfafb36dc450fc8962d2cb7 \ + --hash=sha256:9235fa319993405ae5505bf1333366388add2e06848db7b3deee8f990b69808e \ + --hash=sha256:93a0833c10a967effcd823b4e7445ec491f0bf6da5de0ca33629c0528f42b748 \ + --hash=sha256:95207503c41b97e7ecc7e596d84a61f441b4935f11aa8332828a754e7ada8c82 \ + --hash=sha256:9df4ab5594fdd208dcba81be815fa8a8a5d8dedaf3b346cbf8b61c7296246a7a \ + --hash=sha256:a920fee41f7d0259f5f72c1f1eb331bc26ffbdc952846f9bd8c3b119013bb52c \ + --hash=sha256:a9de02be53b6bb98efe0b9eda84ffa1ec027fcb23a2de62c4f941d9a2f2f3330 \ + --hash=sha256:ae2fd94c9fe048c94838badcc6e992d033cb9473eb31e5710b3707cba5e8aee2 \ + --hash=sha256:b3337804ea0394a06e916add4e5fac1c89902f1b6f33936074a12505cab4ff05 \ + --hash=sha256:ba164e73fdade9b4614a2497321c5b7512ddf749ed508950bdecc28d8d76a2d9 \ + --hash=sha256:bb99f003c720c6d83be02c8f1a7787c22384a8ca9a4181e406174db47a048619 \ + --hash=sha256:ca6f700cff6833de4872a4e738f43123db34400173558b558ae079b5535857a4 \ + --hash=sha256:cec237c305fcbeef75c0bcbe9d223d1e22a6e3ba1b53b2f0b79d3d29c742b45b \ + --hash=sha256:dabe8bf1ad644e6b93f3acf90ff18536d94538ca4d27e583c6db49889e98e48f \ + --hash=sha256:dac78a650dc0637d610905fd06b5fa6419ae9028cf4d04d6a2657bc18a66bbce \ + --hash=sha256:dcc07b1277e8b4bf4d7382ca133850e323b7ab048b8353af496d050671c7ac52 \ + --hash=sha256:e0a15665b2d6cf364f4cd114d62452ce01d71abfbd9c564ba8c74dcd7bbd6822 \ + --hash=sha256:e0e961923a7b8a1c801c43552dcb8153e45afa41749d9efbd3a6d33f45489f7a \ + --hash=sha256:e4a65567bd17d19f03157c7ec992c6530eafd8191a4e5ede25566792c4fe3fa2 \ + --hash=sha256:e5d55f2a82e5eb23795f724991cac2bffbb1c0f219c0ba3bf73a835f97f1bb2e \ + --hash=sha256:e699aa68c4a7dea2ab5a27067f7d3e08555f8d2c0dc6a0c8c60cfd9ff2e6a4b1 \ + --hash=sha256:e974ab16a60be71a8dfad4e5afccf8dd05d41c758060f5d5bda9a758605d9a5d \ + --hash=sha256:ee4c86d8e6872a61f7888fc96577b0ea165eb3bdb0d841962b444fa36001e2bb \ + --hash=sha256:f1945d48fb9b8a87d515da07f37e5b2c35b364a435f534c122e92747881f4a7c \ + --hash=sha256:f2bc1ee4b1ca2c4e7e6b7a5e892126335ec8d9215bcd3ac2fe075870fefc3358 \ + --hash=sha256:fb104c3c2a78d9d85571c8ac90ec4f95bca9b297c6eee5ada71fabf1129e1674 \ + --hash=sha256:fbedc4617faa0edf423621bb0b3b8707836687161210d470e69a4184be9ca011 \ + --hash=sha256:fdeba88c540c9ed0338c0b2062d9f81af42b18d6646b3e6dda05cf6edd46ada9 pynacl==1.5.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:06b8f6fa7f5de8d5d2f7573fe8c863c051225a27b61e6860fd047b1775807858 \ --hash=sha256:0c84947a22519e013607c9be43706dd42513f9e6ae5d39d3613ca1e142fba44d \ @@ -1337,47 +1213,6 @@ python-dateutil==2.8.2 ; python_version >= "3.10" and python_version < "4.0" \ python-dotenv==1.0.1 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:e324ee90a023d808f1959c46bcbc04446a10ced277783dc6ee09987c37ec10ca \ --hash=sha256:f7b63ef50f1b690dddf550d03497b66d609393b40b564ed0d674909a68ebf16a -python-flirt==0.8.10 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:02792127c579d624a98c8f65a1b6f2b27c2d8be673a4ae3e26d9b42543051cf3 \ - --hash=sha256:055412a990b471acc2ce16d9372e4a1af379a81bc54bedd864d35f5f63c8b010 \ - --hash=sha256:0b79ee2a6b0a098225510ab5cc0d54f1534ecfd4c647b3a614ce9dca9615d13a \ - --hash=sha256:0d2f444799bc2b73271fb6e0715f9ccb831308999051ca58f121282499a955b1 \ - --hash=sha256:0db5c5d9a8920cdb32fd1dbff8fe00e99d32fd9d478b15317093e23942c0aef6 \ - --hash=sha256:166d27e034118562aa95d7b403a5b111d5ba8469fe14dd4077b081bee7266d00 \ - --hash=sha256:19e38ea51af68113d88e180c339873d202bef8637532a2c9173dbac38ff4aece \ - --hash=sha256:2547d34b146ab18bf64c1eceb46be0643d903bbf396aabe79d07ed8475893cea \ - --hash=sha256:2b0e285a582576c2ddba9af17a97fbfdd52187fbf098a797df9e00034000796d \ - --hash=sha256:2d8ab2d51b26502415a7a3cd82eb825252be508d7f32d870440fd1096b444232 \ - --hash=sha256:2f4cebbf3cba105f5f0db64a030109c966f4aecb29f94c7ac6e4594f3d4b3c63 \ - --hash=sha256:30960a682673bb25ae2bd8ba7c754e9e18faa4427fe75fe29d5fc341fa974346 \ - --hash=sha256:354814081fcba58f5448ef8bd3b3a7814cce2cb1ed7ad9c1d572447bc85f9e7a \ - --hash=sha256:38e96fdf79b6e4b6b86b37d33278c8522eb41972a17d98d8924d3772c527ecd8 \ - --hash=sha256:4bfe6e2b8eb0e587476fab7db21a15fb40e96e944f404e872c906d89450a52bc \ - --hash=sha256:4fb8d48f304ef6394dee74a5d6b1e31f9b91bc046305ea6ee1f26d8e28229cb4 \ - --hash=sha256:547fc7d8567db0332b229be0551c3aa65c839d439fdd317b7184edb491dde322 \ - --hash=sha256:5d3172c9ac87d36add8eb15d42f33636d408516c7e4834dd572836ef5f4e9e26 \ - --hash=sha256:6745709e936c19100190c52220adda8290dd6bad31d8f708cf3c52deb87546d9 \ - --hash=sha256:6897be2d12fed520524259640648f5022c3c1bff2bf2da10f018315823cc4134 \ - --hash=sha256:6c3185790d3f3749ea2cb984f10259d533ad54036b5878cedcd4149ce3122d5e \ - --hash=sha256:729002c7a6a15905a8dd60b646d5a28605ca73ed8a62886caaf3a49cfeb5a7bf \ - --hash=sha256:82b820c27a4f8f94804aa42617e8d5cb80e76ca55bd89b656ff3924dae8af293 \ - --hash=sha256:877a99236e7e37f4e94f223297e9029ab14426a4d4d5f7a621a1719b0375dda1 \ - --hash=sha256:8da95d051a6bbcebb3043541adfb3dd635b792a837e8ac829c017549ba00d977 \ - --hash=sha256:9b5a285ea80a63d68af56fb406de5ab263ab1b6c988def94c76ebe91d1e9eeec \ - --hash=sha256:a19cbf0a2c87decb8d861b74a499eb4b3fd6fc65ac73227d6330641a5d070c6c \ - --hash=sha256:a59b5c26a12038484ece6bb66eb2e45c286fe476f5a4bed5e8f4e5dabba63991 \ - --hash=sha256:acedddf5acd384626c55b7ed2bda71a5651eb7aed3be1d7098507ea0d3adaabb \ - --hash=sha256:b17592ac73c49515f4c7ae4945060dea18685bdfb320f0bbcd0f613d11492dbb \ - --hash=sha256:b927124c042863d7d488c3b64796c6c690252f1b4f9cbe1135681c6918e53d99 \ - --hash=sha256:b9bb40cb897458ac0d9af121e35aa28ea33ea1a9eadf33bbf79ff84a81f2eaf4 \ - --hash=sha256:c14ff6b3a9dd1d0629d247688e8e69d348dab9df2f654b0f2424343f66446ce5 \ - --hash=sha256:c1f8e406d15f31049ff558534b4be952fb073aadc2e7174e650f4a71256282c6 \ - --hash=sha256:cb173f1030cd05f586f20b68c594bdc54f745d4fb12dc8db100dc70127a771d7 \ - --hash=sha256:cc1b020e54f119916f7cdac4a24f692643915af83d51e2f73f35472da16213ac \ - --hash=sha256:ce6f443bec1ac970e41c8238e945b6f08af402bab32256c6b818143acd0a86d6 \ - --hash=sha256:d0102bfdda68ce2050cfb61cd2e8bbc8225bc2b5a0535fb492e12c42d9dbf23a \ - --hash=sha256:f21d7e23a82ba6cfcde4fc252cd998af8848b7e5bbd7b8c670384073d3b7ad66 \ - --hash=sha256:fc7e6041c7e146328a6daf05303590aa18251c0e5cf92f8b93e8f1eafaadb7a7 python-magic==0.4.27 ; python_version >= "3.10" and sys_platform == "linux" and python_version < "4.0" \ --hash=sha256:c1ba14b08e4a5f5c31a302b7721239695b2f0f058d125bd5ce1ee36b9d9d3c3b \ --hash=sha256:c212960ad306f700aa0d01e5d7a325d20548ff97eb9920dcd29513174f0294d3 @@ -1448,65 +1283,104 @@ pyyaml==6.0.2 ; python_version >= "3.10" and python_version < "4.0" \ pyzipper==0.3.5 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:6040069654dad040cf8708d4db78ce5829238e2091ad8006a47d97d6ffe275d6 \ --hash=sha256:e696e9d306427400e23e13a766c7614b64d9fc3316bdc71bbcc8f0070a14f150 -rat-king-parser @ git+https://github.com/jeFF0Falltrades/rat_king_parser@ab849ec8face38c8dac3f803ae5fe7cf8be26583 ; python_version >= "3.10" and python_version < "4.0" -regex==2021.7.6 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:0eb2c6e0fcec5e0f1d3bcc1133556563222a2ffd2211945d7b1480c1b1a42a6f \ - --hash=sha256:15dddb19823f5147e7517bb12635b3c82e6f2a3a6b696cc3e321522e8b9308ad \ - --hash=sha256:173bc44ff95bc1e96398c38f3629d86fa72e539c79900283afa895694229fe6a \ - --hash=sha256:17d8a3f99b18d87ac54a449b836d485cc8c195bb6f5e4379c84c8519045facc9 \ - --hash=sha256:1947e7de155063e1c495c50590229fb98720d4c383af5031bbcb413db33fa1be \ - --hash=sha256:1c78780bf46d620ff4fff40728f98b8afd8b8e35c3efd638c7df67be2d5cddbf \ - --hash=sha256:2366fe0479ca0e9afa534174faa2beae87847d208d457d200183f28c74eaea59 \ - --hash=sha256:2bceeb491b38225b1fee4517107b8491ba54fba77cf22a12e996d96a3c55613d \ - --hash=sha256:2ddeabc7652024803666ea09f32dd1ed40a0579b6fbb2a213eba590683025895 \ - --hash=sha256:2fe5e71e11a54e3355fa272137d521a40aace5d937d08b494bed4529964c19c4 \ - --hash=sha256:319eb2a8d0888fa6f1d9177705f341bc9455a2c8aca130016e52c7fe8d6c37a3 \ - --hash=sha256:3f5716923d3d0bfb27048242a6e0f14eecdb2e2a7fac47eda1d055288595f222 \ - --hash=sha256:3fabb19c82ecf39832a3f5060dfea9a7ab270ef156039a1143a29a83a09a62de \ - --hash=sha256:422dec1e7cbb2efbbe50e3f1de36b82906def93ed48da12d1714cabcd993d7f0 \ - --hash=sha256:4c9c3155fe74269f61e27617529b7f09552fbb12e44b1189cebbdb24294e6e1c \ - --hash=sha256:4f64fc59fd5b10557f6cd0937e1597af022ad9b27d454e182485f1db3008f417 \ - --hash=sha256:564a4c8a29435d1f2256ba247a0315325ea63335508ad8ed938a4f14c4116a5d \ - --hash=sha256:56fc7045a1999a8d9dd1896715bc5c802dfec5b9b60e883d2cbdecb42adedea4 \ - --hash=sha256:59506c6e8bd9306cd8a41511e32d16d5d1194110b8cfe5a11d102d8b63cf945d \ - --hash=sha256:598c0a79b4b851b922f504f9f39a863d83ebdfff787261a5ed061c21e67dd761 \ - --hash=sha256:598ee917dbe961dcf827217bf2466bb86e4ee5a8559705af57cbabb3489dd37e \ - --hash=sha256:59c00bb8dd8775473cbfb967925ad2c3ecc8886b3b2d0c90a8e2707e06c743f0 \ - --hash=sha256:6110bab7eab6566492618540c70edd4d2a18f40ca1d51d704f1d81c52d245026 \ - --hash=sha256:6afe6a627888c9a6cfbb603d1d017ce204cebd589d66e0703309b8048c3b0854 \ - --hash=sha256:716a6db91b3641f566531ffcc03ceec00b2447f0db9942b3c6ea5d2827ad6be3 \ - --hash=sha256:7423aca7cc30a6228ccdcf2ea76f12923d652c5c7c6dc1959a0b004e308f39fb \ - --hash=sha256:791aa1b300e5b6e5d597c37c346fb4d66422178566bbb426dd87eaae475053fb \ - --hash=sha256:8244c681018423a0d1784bc6b9af33bdf55f2ab8acb1f3cd9dd83d90e0813253 \ - --hash=sha256:8394e266005f2d8c6f0bc6780001f7afa3ef81a7a2111fa35058ded6fce79e4d \ - --hash=sha256:875c355360d0f8d3d827e462b29ea7682bf52327d500a4f837e934e9e4656068 \ - --hash=sha256:89e5528803566af4df368df2d6f503c84fbfb8249e6631c7b025fe23e6bd0cde \ - --hash=sha256:8a4c742089faf0e51469c6a1ad7e3d3d21afae54a16a6cead85209dfe0a1ce65 \ - --hash=sha256:914e626dc8e75fe4fc9b7214763f141d9f40165d00dfe680b104fa1b24063bbf \ - --hash=sha256:99d8ab206a5270c1002bfcf25c51bf329ca951e5a169f3b43214fdda1f0b5f0d \ - --hash=sha256:9a854b916806c7e3b40e6616ac9e85d3cdb7649d9e6590653deb5b341a736cec \ - --hash=sha256:b85ac458354165405c8a84725de7bbd07b00d9f72c31a60ffbf96bb38d3e25fa \ - --hash=sha256:bb9834c1e77493efd7343b8e38950dee9797d2d6f2d5fd91c008dfaef64684b9 \ - --hash=sha256:bc84fb254a875a9f66616ed4538542fb7965db6356f3df571d783f7c8d256edd \ - --hash=sha256:bf1d2d183abc7faa101ebe0b8d04fd19cb9138820abc8589083035c9440b8ca6 \ - --hash=sha256:c92831dac113a6e0ab28bc98f33781383fe294df1a2c3dfd1e850114da35fd5b \ - --hash=sha256:cbe23b323988a04c3e5b0c387fe3f8f363bf06c0680daf775875d979e376bd26 \ - --hash=sha256:ccb3d2190476d00414aab36cca453e4596e8f70a206e2aa8db3d495a109153d2 \ - --hash=sha256:d30895ec80cc80358392841add9dde81ea1d54a4949049269115e6b0555d0498 \ - --hash=sha256:d8bbce0c96462dbceaa7ac4a7dfbbee92745b801b24bce10a98d2f2b1ea9432f \ - --hash=sha256:db2b7df831c3187a37f3bb80ec095f249fa276dbe09abd3d35297fc250385694 \ - --hash=sha256:dfc0957c4a4b91eff5ad036088769e600a25774256cd0e1154378591ce573f08 \ - --hash=sha256:e586f448df2bbc37dfadccdb7ccd125c62b4348cb90c10840d695592aa1b29e0 \ - --hash=sha256:e5983c19d0beb6af88cb4d47afb92d96751fb3fa1784d8785b1cdf14c6519407 \ - --hash=sha256:e6a1e5ca97d411a461041d057348e578dc344ecd2add3555aedba3b408c9f874 \ - --hash=sha256:e8363ac90ea63c3dd0872dfdb695f38aff3334bfa5712cffb238bd3ffef300e3 \ - --hash=sha256:eaf58b9e30e0e546cdc3ac06cf9165a1ca5b3de8221e9df679416ca667972035 \ - --hash=sha256:ed693137a9187052fc46eedfafdcb74e09917166362af4cc4fddc3b31560e93d \ - --hash=sha256:edd1a68f79b89b0c57339bce297ad5d5ffcc6ae7e1afdb10f1947706ed066c9c \ - --hash=sha256:efb4af05fa4d2fc29766bf516f1f5098d6b5c3ed846fde980c18bf8646ad3979 \ - --hash=sha256:f080248b3e029d052bf74a897b9d74cfb7643537fbde97fe8225a6467fb559b5 \ - --hash=sha256:f9392a4555f3e4cb45310a65b403d86b589adc773898c25a39184b1ba4db8985 \ - --hash=sha256:f98dc35ab9a749276f1a4a38ab3e0e2ba1662ce710f6530f5b0a6656f1c32b58 +rat-king-parser==3.1.3 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:229c7d4565e7c0ea3e6a75a8252df9223286a26b77b2d449c2612b95c8406605 \ + --hash=sha256:cd662eb127c1bb85345a4460439608cfc87b82e833503b632d5ccc713eb49123 +regex==2024.9.11 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:01c2acb51f8a7d6494c8c5eafe3d8e06d76563d8a8a4643b37e9b2dd8a2ff623 \ + --hash=sha256:02087ea0a03b4af1ed6ebab2c54d7118127fee8d71b26398e8e4b05b78963199 \ + --hash=sha256:040562757795eeea356394a7fb13076ad4f99d3c62ab0f8bdfb21f99a1f85664 \ + --hash=sha256:042c55879cfeb21a8adacc84ea347721d3d83a159da6acdf1116859e2427c43f \ + --hash=sha256:079400a8269544b955ffa9e31f186f01d96829110a3bf79dc338e9910f794fca \ + --hash=sha256:07f45f287469039ffc2c53caf6803cd506eb5f5f637f1d4acb37a738f71dd066 \ + --hash=sha256:09d77559e80dcc9d24570da3745ab859a9cf91953062e4ab126ba9d5993688ca \ + --hash=sha256:0cbff728659ce4bbf4c30b2a1be040faafaa9eca6ecde40aaff86f7889f4ab39 \ + --hash=sha256:0e12c481ad92d129c78f13a2a3662317e46ee7ef96c94fd332e1c29131875b7d \ + --hash=sha256:0ea51dcc0835eea2ea31d66456210a4e01a076d820e9039b04ae8d17ac11dee6 \ + --hash=sha256:0ffbcf9221e04502fc35e54d1ce9567541979c3fdfb93d2c554f0ca583a19b35 \ + --hash=sha256:1494fa8725c285a81d01dc8c06b55287a1ee5e0e382d8413adc0a9197aac6408 \ + --hash=sha256:16e13a7929791ac1216afde26f712802e3df7bf0360b32e4914dca3ab8baeea5 \ + --hash=sha256:18406efb2f5a0e57e3a5881cd9354c1512d3bb4f5c45d96d110a66114d84d23a \ + --hash=sha256:18e707ce6c92d7282dfce370cd205098384b8ee21544e7cb29b8aab955b66fa9 \ + --hash=sha256:220e92a30b426daf23bb67a7962900ed4613589bab80382be09b48896d211e92 \ + --hash=sha256:23b30c62d0f16827f2ae9f2bb87619bc4fba2044911e2e6c2eb1af0161cdb766 \ + --hash=sha256:23f9985c8784e544d53fc2930fc1ac1a7319f5d5332d228437acc9f418f2f168 \ + --hash=sha256:297f54910247508e6e5cae669f2bc308985c60540a4edd1c77203ef19bfa63ca \ + --hash=sha256:2b08fce89fbd45664d3df6ad93e554b6c16933ffa9d55cb7e01182baaf971508 \ + --hash=sha256:2cce2449e5927a0bf084d346da6cd5eb016b2beca10d0013ab50e3c226ffc0df \ + --hash=sha256:313ea15e5ff2a8cbbad96ccef6be638393041b0a7863183c2d31e0c6116688cf \ + --hash=sha256:323c1f04be6b2968944d730e5c2091c8c89767903ecaa135203eec4565ed2b2b \ + --hash=sha256:35f4a6f96aa6cb3f2f7247027b07b15a374f0d5b912c0001418d1d55024d5cb4 \ + --hash=sha256:3b37fa423beefa44919e009745ccbf353d8c981516e807995b2bd11c2c77d268 \ + --hash=sha256:3ce4f1185db3fbde8ed8aa223fc9620f276c58de8b0d4f8cc86fd1360829edb6 \ + --hash=sha256:46989629904bad940bbec2106528140a218b4a36bb3042d8406980be1941429c \ + --hash=sha256:4838e24ee015101d9f901988001038f7f0d90dc0c3b115541a1365fb439add62 \ + --hash=sha256:49b0e06786ea663f933f3710a51e9385ce0cba0ea56b67107fd841a55d56a231 \ + --hash=sha256:4db21ece84dfeefc5d8a3863f101995de646c6cb0536952c321a2650aa202c36 \ + --hash=sha256:54c4a097b8bc5bb0dfc83ae498061d53ad7b5762e00f4adaa23bee22b012e6ba \ + --hash=sha256:54d9ff35d4515debf14bc27f1e3b38bfc453eff3220f5bce159642fa762fe5d4 \ + --hash=sha256:55b96e7ce3a69a8449a66984c268062fbaa0d8ae437b285428e12797baefce7e \ + --hash=sha256:57fdd2e0b2694ce6fc2e5ccf189789c3e2962916fb38779d3e3521ff8fe7a822 \ + --hash=sha256:587d4af3979376652010e400accc30404e6c16b7df574048ab1f581af82065e4 \ + --hash=sha256:5b513b6997a0b2f10e4fd3a1313568e373926e8c252bd76c960f96fd039cd28d \ + --hash=sha256:5ddcd9a179c0a6fa8add279a4444015acddcd7f232a49071ae57fa6e278f1f71 \ + --hash=sha256:6113c008a7780792efc80f9dfe10ba0cd043cbf8dc9a76ef757850f51b4edc50 \ + --hash=sha256:635a1d96665f84b292e401c3d62775851aedc31d4f8784117b3c68c4fcd4118d \ + --hash=sha256:64ce2799bd75039b480cc0360907c4fb2f50022f030bf9e7a8705b636e408fad \ + --hash=sha256:69dee6a020693d12a3cf892aba4808fe168d2a4cef368eb9bf74f5398bfd4ee8 \ + --hash=sha256:6a2644a93da36c784e546de579ec1806bfd2763ef47babc1b03d765fe560c9f8 \ + --hash=sha256:6b41e1adc61fa347662b09398e31ad446afadff932a24807d3ceb955ed865cc8 \ + --hash=sha256:6c188c307e8433bcb63dc1915022deb553b4203a70722fc542c363bf120a01fd \ + --hash=sha256:6edd623bae6a737f10ce853ea076f56f507fd7726bee96a41ee3d68d347e4d16 \ + --hash=sha256:73d6d2f64f4d894c96626a75578b0bf7d9e56dcda8c3d037a2118fdfe9b1c664 \ + --hash=sha256:7a22ccefd4db3f12b526eccb129390942fe874a3a9fdbdd24cf55773a1faab1a \ + --hash=sha256:7fb89ee5d106e4a7a51bce305ac4efb981536301895f7bdcf93ec92ae0d91c7f \ + --hash=sha256:846bc79ee753acf93aef4184c040d709940c9d001029ceb7b7a52747b80ed2dd \ + --hash=sha256:85ab7824093d8f10d44330fe1e6493f756f252d145323dd17ab6b48733ff6c0a \ + --hash=sha256:8dee5b4810a89447151999428fe096977346cf2f29f4d5e29609d2e19e0199c9 \ + --hash=sha256:8e5fb5f77c8745a60105403a774fe2c1759b71d3e7b4ca237a5e67ad066c7199 \ + --hash=sha256:98eeee2f2e63edae2181c886d7911ce502e1292794f4c5ee71e60e23e8d26b5d \ + --hash=sha256:9d4a76b96f398697fe01117093613166e6aa8195d63f1b4ec3f21ab637632963 \ + --hash=sha256:9e8719792ca63c6b8340380352c24dcb8cd7ec49dae36e963742a275dfae6009 \ + --hash=sha256:a0b2b80321c2ed3fcf0385ec9e51a12253c50f146fddb2abbb10f033fe3d049a \ + --hash=sha256:a4cc92bb6db56ab0c1cbd17294e14f5e9224f0cc6521167ef388332604e92679 \ + --hash=sha256:a738b937d512b30bf75995c0159c0ddf9eec0775c9d72ac0202076c72f24aa96 \ + --hash=sha256:a8f877c89719d759e52783f7fe6e1c67121076b87b40542966c02de5503ace42 \ + --hash=sha256:a906ed5e47a0ce5f04b2c981af1c9acf9e8696066900bf03b9d7879a6f679fc8 \ + --hash=sha256:ae2941333154baff9838e88aa71c1d84f4438189ecc6021a12c7573728b5838e \ + --hash=sha256:b0d0a6c64fcc4ef9c69bd5b3b3626cc3776520a1637d8abaa62b9edc147a58f7 \ + --hash=sha256:b5b029322e6e7b94fff16cd120ab35a253236a5f99a79fb04fda7ae71ca20ae8 \ + --hash=sha256:b7aaa315101c6567a9a45d2839322c51c8d6e81f67683d529512f5bcfb99c802 \ + --hash=sha256:be1c8ed48c4c4065ecb19d882a0ce1afe0745dfad8ce48c49586b90a55f02366 \ + --hash=sha256:c0256beda696edcf7d97ef16b2a33a8e5a875affd6fa6567b54f7c577b30a137 \ + --hash=sha256:c157bb447303070f256e084668b702073db99bbb61d44f85d811025fcf38f784 \ + --hash=sha256:c57d08ad67aba97af57a7263c2d9006d5c404d721c5f7542f077f109ec2a4a29 \ + --hash=sha256:c69ada171c2d0e97a4b5aa78fbb835e0ffbb6b13fc5da968c09811346564f0d3 \ + --hash=sha256:c94bb0a9f1db10a1d16c00880bdebd5f9faf267273b8f5bd1878126e0fbde771 \ + --hash=sha256:cb130fccd1a37ed894824b8c046321540263013da72745d755f2d35114b81a60 \ + --hash=sha256:ced479f601cd2f8ca1fd7b23925a7e0ad512a56d6e9476f79b8f381d9d37090a \ + --hash=sha256:d05ac6fa06959c4172eccd99a222e1fbf17b5670c4d596cb1e5cde99600674c4 \ + --hash=sha256:d552c78411f60b1fdaafd117a1fca2f02e562e309223b9d44b7de8be451ec5e0 \ + --hash=sha256:dd4490a33eb909ef5078ab20f5f000087afa2a4daa27b4c072ccb3cb3050ad84 \ + --hash=sha256:df5cbb1fbc74a8305b6065d4ade43b993be03dbe0f8b30032cced0d7740994bd \ + --hash=sha256:e28f9faeb14b6f23ac55bfbbfd3643f5c7c18ede093977f1df249f73fd22c7b1 \ + --hash=sha256:e464b467f1588e2c42d26814231edecbcfe77f5ac414d92cbf4e7b55b2c2a776 \ + --hash=sha256:e4c22e1ac1f1ec1e09f72e6c44d8f2244173db7eb9629cc3a346a8d7ccc31142 \ + --hash=sha256:e53b5fbab5d675aec9f0c501274c467c0f9a5d23696cfc94247e1fb56501ed89 \ + --hash=sha256:e93f1c331ca8e86fe877a48ad64e77882c0c4da0097f2212873a69bbfea95d0c \ + --hash=sha256:e997fd30430c57138adc06bba4c7c2968fb13d101e57dd5bb9355bf8ce3fa7e8 \ + --hash=sha256:e9a091b0550b3b0207784a7d6d0f1a00d1d1c8a11699c1a4d93db3fbefc3ad35 \ + --hash=sha256:eab4bb380f15e189d1313195b062a6aa908f5bd687a0ceccd47c8211e9cf0d4a \ + --hash=sha256:eb1ae19e64c14c7ec1995f40bd932448713d3c73509e82d8cd7744dc00e29e86 \ + --hash=sha256:ecea58b43a67b1b79805f1a0255730edaf5191ecef84dbc4cc85eb30bc8b63b9 \ + --hash=sha256:ee439691d8c23e76f9802c42a95cfeebf9d47cf4ffd06f18489122dbb0a7ad64 \ + --hash=sha256:eee9130eaad130649fd73e5cd92f60e55708952260ede70da64de420cdcad554 \ + --hash=sha256:f47cd43a5bfa48f86925fe26fbdd0a488ff15b62468abb5d2a1e092a4fb10e85 \ + --hash=sha256:f6fff13ef6b5f29221d6904aa816c34701462956aa72a77f1f151a8ec4f56aeb \ + --hash=sha256:f745ec09bc1b0bd15cfc73df6fa4f726dcc26bb16c23a03f9e3367d357eeedd0 \ + --hash=sha256:f8404bf61298bb6f8224bb9176c1424548ee1181130818fcd2cbffddc768bed8 \ + --hash=sha256:f9268774428ec173654985ce55fc6caf4c6d11ade0f6f914d48ef4719eb05ebb \ + --hash=sha256:faa3c142464efec496967359ca99696c896c591c56c53506bac1ad465f66e919 requests-file==1.5.1 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:07d74208d3389d01c38ab89ef403af0cfec63957d53a0081d8eca738d0247d8e \ --hash=sha256:dfe5dae75c12481f68ba353183c53a65e6044c923e64c24b2209f6c7570ca953 @@ -1519,63 +1393,6 @@ requests==2.32.2 ; python_version >= "3.10" and python_version < "4.0" \ requests[security,socks]==2.32.2 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:dd951ff5ecf3e3b3aa26b40703ba77495dab41da839ae72ef3c8e5d8e2433289 \ --hash=sha256:fc06670dd0ed212426dfeb94fc1b983d917c4f9847c863f313c9dfaaffb7c23c -rich==13.8.1 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:1760a3c0848469b97b558fc61c85233e3dafb69c7a071b4d60c38099d3cd4c06 \ - --hash=sha256:8260cda28e3db6bf04d2d1ef4dbc03ba80a824c88b0e7668a0f23126a424844a -ruamel-yaml-clib==0.2.8 ; platform_python_implementation == "CPython" and python_version < "3.13" and python_version >= "3.10" \ - --hash=sha256:024cfe1fc7c7f4e1aff4a81e718109e13409767e4f871443cbff3dba3578203d \ - --hash=sha256:03d1162b6d1df1caa3a4bd27aa51ce17c9afc2046c31b0ad60a0a96ec22f8001 \ - --hash=sha256:07238db9cbdf8fc1e9de2489a4f68474e70dffcb32232db7c08fa61ca0c7c462 \ - --hash=sha256:09b055c05697b38ecacb7ac50bdab2240bfca1a0c4872b0fd309bb07dc9aa3a9 \ - --hash=sha256:1707814f0d9791df063f8c19bb51b0d1278b8e9a2353abbb676c2f685dee6afe \ - --hash=sha256:1758ce7d8e1a29d23de54a16ae867abd370f01b5a69e1a3ba75223eaa3ca1a1b \ - --hash=sha256:184565012b60405d93838167f425713180b949e9d8dd0bbc7b49f074407c5a8b \ - --hash=sha256:1b617618914cb00bf5c34d4357c37aa15183fa229b24767259657746c9077615 \ - --hash=sha256:1dc67314e7e1086c9fdf2680b7b6c2be1c0d8e3a8279f2e993ca2a7545fecf62 \ - --hash=sha256:25ac8c08322002b06fa1d49d1646181f0b2c72f5cbc15a85e80b4c30a544bb15 \ - --hash=sha256:25c515e350e5b739842fc3228d662413ef28f295791af5e5110b543cf0b57d9b \ - --hash=sha256:305889baa4043a09e5b76f8e2a51d4ffba44259f6b4c72dec8ca56207d9c6fe1 \ - --hash=sha256:3213ece08ea033eb159ac52ae052a4899b56ecc124bb80020d9bbceeb50258e9 \ - --hash=sha256:3f215c5daf6a9d7bbed4a0a4f760f3113b10e82ff4c5c44bec20a68c8014f675 \ - --hash=sha256:46d378daaac94f454b3a0e3d8d78cafd78a026b1d71443f4966c696b48a6d899 \ - --hash=sha256:4ecbf9c3e19f9562c7fdd462e8d18dd902a47ca046a2e64dba80699f0b6c09b7 \ - --hash=sha256:53a300ed9cea38cf5a2a9b069058137c2ca1ce658a874b79baceb8f892f915a7 \ - --hash=sha256:56f4252222c067b4ce51ae12cbac231bce32aee1d33fbfc9d17e5b8d6966c312 \ - --hash=sha256:5c365d91c88390c8d0a8545df0b5857172824b1c604e867161e6b3d59a827eaa \ - --hash=sha256:700e4ebb569e59e16a976857c8798aee258dceac7c7d6b50cab63e080058df91 \ - --hash=sha256:75e1ed13e1f9de23c5607fe6bd1aeaae21e523b32d83bb33918245361e9cc51b \ - --hash=sha256:77159f5d5b5c14f7c34073862a6b7d34944075d9f93e681638f6d753606c6ce6 \ - --hash=sha256:7f67a1ee819dc4562d444bbafb135832b0b909f81cc90f7aa00260968c9ca1b3 \ - --hash=sha256:840f0c7f194986a63d2c2465ca63af8ccbbc90ab1c6001b1978f05119b5e7334 \ - --hash=sha256:84b554931e932c46f94ab306913ad7e11bba988104c5cff26d90d03f68258cd5 \ - --hash=sha256:87ea5ff66d8064301a154b3933ae406b0863402a799b16e4a1d24d9fbbcbe0d3 \ - --hash=sha256:955eae71ac26c1ab35924203fda6220f84dce57d6d7884f189743e2abe3a9fbe \ - --hash=sha256:a1a45e0bb052edf6a1d3a93baef85319733a888363938e1fc9924cb00c8df24c \ - --hash=sha256:a5aa27bad2bb83670b71683aae140a1f52b0857a2deff56ad3f6c13a017a26ed \ - --hash=sha256:a6a9ffd280b71ad062eae53ac1659ad86a17f59a0fdc7699fd9be40525153337 \ - --hash=sha256:a75879bacf2c987c003368cf14bed0ffe99e8e85acfa6c0bfffc21a090f16880 \ - --hash=sha256:aa2267c6a303eb483de8d02db2871afb5c5fc15618d894300b88958f729ad74f \ - --hash=sha256:aab7fd643f71d7946f2ee58cc88c9b7bfc97debd71dcc93e03e2d174628e7e2d \ - --hash=sha256:b16420e621d26fdfa949a8b4b47ade8810c56002f5389970db4ddda51dbff248 \ - --hash=sha256:b42169467c42b692c19cf539c38d4602069d8c1505e97b86387fcf7afb766e1d \ - --hash=sha256:bba64af9fa9cebe325a62fa398760f5c7206b215201b0ec825005f1b18b9bccf \ - --hash=sha256:beb2e0404003de9a4cab9753a8805a8fe9320ee6673136ed7f04255fe60bb512 \ - --hash=sha256:bef08cd86169d9eafb3ccb0a39edb11d8e25f3dae2b28f5c52fd997521133069 \ - --hash=sha256:c2a72e9109ea74e511e29032f3b670835f8a59bbdc9ce692c5b4ed91ccf1eedb \ - --hash=sha256:c58ecd827313af6864893e7af0a3bb85fd529f862b6adbefe14643947cfe2942 \ - --hash=sha256:c69212f63169ec1cfc9bb44723bf2917cbbd8f6191a00ef3410f5a7fe300722d \ - --hash=sha256:cabddb8d8ead485e255fe80429f833172b4cadf99274db39abc080e068cbcc31 \ - --hash=sha256:d176b57452ab5b7028ac47e7b3cf644bcfdc8cacfecf7e71759f7f51a59e5c92 \ - --hash=sha256:da09ad1c359a728e112d60116f626cc9f29730ff3e0e7db72b9a2dbc2e4beed5 \ - --hash=sha256:e2b4c44b60eadec492926a7270abb100ef9f72798e18743939bdbf037aab8c28 \ - --hash=sha256:e79e5db08739731b0ce4850bed599235d601701d5694c36570a99a0c5ca41a9d \ - --hash=sha256:ebc06178e8821efc9692ea7544aa5644217358490145629914d8020042c24aa1 \ - --hash=sha256:edaef1c1200c4b4cb914583150dcaa3bc30e592e907c01117c08b13a07255ec2 \ - --hash=sha256:f481f16baec5290e45aebdc2a5168ebc6d35189ae6fea7a58787613a25f6e875 \ - --hash=sha256:fff3573c2db359f091e1589c3d7c5fc2f86f5bdb6f24252c2d8e539d4e45f412 -ruamel-yaml==0.18.6 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:57b53ba33def16c4f3d807c0ccbc00f8a6081827e81ba2491691b76882d0c636 \ - --hash=sha256:8b27e6a217e786c6fbe5634d8f3f11bc63e0f80f6a5890f28863d9c45aac311b ruff==0.0.290 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:0e2b09ac4213b11a3520221083866a5816616f3ae9da123037b8ab275066fbac \ --hash=sha256:150bf8050214cea5b990945b66433bf9a5e0cef395c9bc0f50569e7de7540c86 \ @@ -1594,9 +1411,9 @@ ruff==0.0.290 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:d748c8bd97874f5751aed73e8dde379ce32d16338123d07c18b25c9a2796574a \ --hash=sha256:eb07f37f7aecdbbc91d759c0c09870ce0fb3eed4025eebedf9c4b98c69abd527 \ --hash=sha256:f1f49f5ec967fd5778813780b12a5650ab0ebcb9ddcca28d642c689b36920796 -service-identity==24.1.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:6829c9d62fb832c2e1c435629b0a8c476e1929881f28bee4d20bc24161009221 \ - --hash=sha256:a28caf8130c8a5c1c7a6f5293faaf239bbfb7751e4862436920ee6f2616f568a +service-identity==24.2.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:6b047fbd8a84fd0bb0d55ebce4031e400562b9196e1e0d3e0fe2b8a59f6d4a85 \ + --hash=sha256:b8683ba13f0d39c6cd5d625d2c5f65421d6d707b013b375c355751557cbe8e09 setproctitle==1.3.2 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:1c5d5dad7c28bdd1ec4187d818e43796f58a845aa892bb4481587010dc4d362b \ --hash=sha256:1c8d9650154afaa86a44ff195b7b10d683c73509d085339d174e394a22cccbb9 \ @@ -1682,9 +1499,6 @@ six==1.16.0 ; python_version >= "3.10" and python_version < "4.0" \ sniffio==1.3.1 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2 \ --hash=sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc -sortedcontainers==2.4.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:25caa5a06cc30b6b83d11423433f65d1f9d76c4c6a0c90e3379eaa43b9bfdb88 \ - --hash=sha256:a163dcaede0f1c021485e957a39245190e74249897e2ae4b2aa38595db237ee0 soupsieve==2.6 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:e2e68417777af359ec65daac1057404a3c8a5455bb8abc36f1a9866ab1a51abb \ --hash=sha256:e72c4ff06e4fb6e4b5a9f0f55fe6e81514581fca1515028625d0f299c602ccc9 @@ -1741,24 +1555,15 @@ sqlalchemy==1.4.50 ; python_version >= "3.10" and python_version < "4.0" \ sqlparse==0.5.1 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:773dcbf9a5ab44a090f3441e2180efe2560220203dc2f8c0b0fa141e18b505e4 \ --hash=sha256:bb6b4df465655ef332548e24f08e205afc81b9ab86cb1c45657a7ff173a3a00e -tabulate==0.9.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:0095b12bf5966de529c0feb1fa08671671b3368eec77d7ef7ab114be2c068b3c \ - --hash=sha256:024ca478df22e9340661486f85298cff5f6dcdba14f3813e8830015b9ed1948f -termcolor==2.4.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:9297c0df9c99445c2412e832e882a7884038a25617c60cea2ad69488d4040d63 \ - --hash=sha256:aab9e56047c8ac41ed798fa36d892a37aca6b3e9159f3e0c24bc64a9b3ac7b7a -tldextract==3.5.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:2cb271ca8d06ea1630a1361b58edad14e0cf81f34ce3c90b052854528fe2a281 \ - --hash=sha256:4df1c65b95be61d59428e8611e955e54e6f1d4483d3e8d5733d3a9062155e910 -tomli==2.0.1 ; python_version >= "3.10" and python_version < "3.11" \ - --hash=sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc \ - --hash=sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f -tqdm==4.66.5 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:90279a3770753eafc9194a0364852159802111925aa30eb3f9d85b0e805ac7cd \ - --hash=sha256:e1020aef2e5096702d8a025ac7d16b1577279c9d63f8375b63083e9a5f0fcbad -twisted[tls]==24.7.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:5a60147f044187a127ec7da96d170d49bcce50c6fd36f594e60f4587eff4d394 \ - --hash=sha256:734832ef98108136e222b5230075b1079dad8a3fc5637319615619a7725b0c81 +tldextract==5.1.2 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:4dfc4c277b6b97fa053899fcdb892d2dc27295851ab5fac4e07797b6a21b2e46 \ + --hash=sha256:c9e17f756f05afb5abac04fe8f766e7e70f9fe387adb1859f0f52408ee060200 +tomli==2.0.2 ; python_version >= "3.10" and python_version < "3.11" \ + --hash=sha256:2ebe24485c53d303f690b0ec092806a085f07af5a5aa1464f3931eec36caaa38 \ + --hash=sha256:d46d457a85337051c36524bc5349dd91b1877838e2979ac5ced3e710ed8a60ed +twisted[tls]==24.10.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:02951299672595fea0f70fa2d5f7b5e3d56836157eda68859a6ad6492d36756e \ + --hash=sha256:67aa7c8aa94387385302acf44ade12967c747858c8bcce0f11d38077a11c5326 txaio==23.1.1 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:aaea42f8aad50e0ecfb976130ada140797e9dcb85fad2cf72b0f37f8cefcb490 \ --hash=sha256:f9a9216e976e5e3246dfd112ad7ad55ca915606b60b84a757ac769bd404ff704 @@ -1786,43 +1591,44 @@ urllib3==2.2.3 ; python_version >= "3.10" and python_version < "4.0" \ uvicorn[standard]==0.18.3 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:0abd429ebb41e604ed8d2be6c60530de3408f250e8d2d84967d85ba9e86fe3af \ --hash=sha256:9a66e7c42a2a95222f76ec24a4b754c158261c4696e683b9dadc72b590e0311b -uvloop==0.20.0 ; (sys_platform != "win32" and sys_platform != "cygwin") and platform_python_implementation != "PyPy" and python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:265a99a2ff41a0fd56c19c3838b29bf54d1d177964c300dad388b27e84fd7847 \ - --hash=sha256:2beee18efd33fa6fdb0976e18475a4042cd31c7433c866e8a09ab604c7c22ff2 \ - --hash=sha256:35968fc697b0527a06e134999eef859b4034b37aebca537daeb598b9d45a137b \ - --hash=sha256:36c530d8fa03bfa7085af54a48f2ca16ab74df3ec7108a46ba82fd8b411a2315 \ - --hash=sha256:3a609780e942d43a275a617c0839d85f95c334bad29c4c0918252085113285b5 \ - --hash=sha256:4603ca714a754fc8d9b197e325db25b2ea045385e8a3ad05d3463de725fdf469 \ - --hash=sha256:4b75f2950ddb6feed85336412b9a0c310a2edbcf4cf931aa5cfe29034829676d \ - --hash=sha256:4f44af67bf39af25db4c1ac27e82e9665717f9c26af2369c404be865c8818dcf \ - --hash=sha256:6462c95f48e2d8d4c993a2950cd3d31ab061864d1c226bbf0ee2f1a8f36674b9 \ - --hash=sha256:649c33034979273fa71aa25d0fe120ad1777c551d8c4cd2c0c9851d88fcb13ab \ - --hash=sha256:746242cd703dc2b37f9d8b9f173749c15e9a918ddb021575a0205ec29a38d31e \ - --hash=sha256:77fbc69c287596880ecec2d4c7a62346bef08b6209749bf6ce8c22bbaca0239e \ - --hash=sha256:80dc1b139516be2077b3e57ce1cb65bfed09149e1d175e0478e7a987863b68f0 \ - --hash=sha256:82edbfd3df39fb3d108fc079ebc461330f7c2e33dbd002d146bf7c445ba6e756 \ - --hash=sha256:89e8d33bb88d7263f74dc57d69f0063e06b5a5ce50bb9a6b32f5fcbe655f9e73 \ - --hash=sha256:94707205efbe809dfa3a0d09c08bef1352f5d3d6612a506f10a319933757c006 \ - --hash=sha256:95720bae002ac357202e0d866128eb1ac82545bcf0b549b9abe91b5178d9b541 \ - --hash=sha256:9b04d96188d365151d1af41fa2d23257b674e7ead68cfd61c725a422764062ae \ - --hash=sha256:9d0fba61846f294bce41eb44d60d58136090ea2b5b99efd21cbdf4e21927c56a \ - --hash=sha256:9ebafa0b96c62881d5cafa02d9da2e44c23f9f0cd829f3a32a6aff771449c996 \ - --hash=sha256:a0fac7be202596c7126146660725157d4813aa29a4cc990fe51346f75ff8fde7 \ - --hash=sha256:aea15c78e0d9ad6555ed201344ae36db5c63d428818b4b2a42842b3870127c00 \ - --hash=sha256:b10c2956efcecb981bf9cfb8184d27d5d64b9033f917115a960b83f11bfa0d6b \ - --hash=sha256:b16696f10e59d7580979b420eedf6650010a4a9c3bd8113f24a103dfdb770b10 \ - --hash=sha256:d8c36fdf3e02cec92aed2d44f63565ad1522a499c654f07935c8f9d04db69e95 \ - --hash=sha256:e237f9c1e8a00e7d9ddaa288e535dc337a39bcbf679f290aee9d26df9e72bce9 \ - --hash=sha256:e50289c101495e0d1bb0bfcb4a60adde56e32f4449a67216a1ab2750aa84f037 \ - --hash=sha256:e7d61fe8e8d9335fac1bf8d5d82820b4808dd7a43020c149b63a1ada953d48a6 \ - --hash=sha256:e97152983442b499d7a71e44f29baa75b3b02e65d9c44ba53b10338e98dedb66 \ - --hash=sha256:f0e94b221295b5e69de57a1bd4aeb0b3a29f61be6e1b478bb8a69a73377db7ba \ - --hash=sha256:fee6044b64c965c425b65a4e17719953b96e065c5b7e09b599ff332bb2744bdf -viv-utils[flirt]==0.7.11 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:ab44c428315e014a52dbbaab6862876dd0cd2c930a138a1655c1c5be7270d81b -vivisect==1.2.1 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:62eb383013318efcd42f2565e4ab5323ebb1fb6b2e8e9e7e432bd126743eccda \ - --hash=sha256:cc15ab541b9be3cad8060ee4f420e680258fa4fcf7477f3f9ad5023353f73299 +uvloop==0.21.0 ; (sys_platform != "win32" and sys_platform != "cygwin") and platform_python_implementation != "PyPy" and python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:0878c2640cf341b269b7e128b1a5fed890adc4455513ca710d77d5e93aa6d6a0 \ + --hash=sha256:10d66943def5fcb6e7b37310eb6b5639fd2ccbc38df1177262b0640c3ca68c1f \ + --hash=sha256:10da8046cc4a8f12c91a1c39d1dd1585c41162a15caaef165c2174db9ef18bdc \ + --hash=sha256:17df489689befc72c39a08359efac29bbee8eee5209650d4b9f34df73d22e414 \ + --hash=sha256:183aef7c8730e54c9a3ee3227464daed66e37ba13040bb3f350bc2ddc040f22f \ + --hash=sha256:196274f2adb9689a289ad7d65700d37df0c0930fd8e4e743fa4834e850d7719d \ + --hash=sha256:221f4f2a1f46032b403bf3be628011caf75428ee3cc204a22addf96f586b19fd \ + --hash=sha256:2d1f581393673ce119355d56da84fe1dd9d2bb8b3d13ce792524e1607139feff \ + --hash=sha256:359ec2c888397b9e592a889c4d72ba3d6befba8b2bb01743f72fffbde663b59c \ + --hash=sha256:3bf12b0fda68447806a7ad847bfa591613177275d35b6724b1ee573faa3704e3 \ + --hash=sha256:4509360fcc4c3bd2c70d87573ad472de40c13387f5fda8cb58350a1d7475e58d \ + --hash=sha256:460def4412e473896ef179a1671b40c039c7012184b627898eea5072ef6f017a \ + --hash=sha256:461d9ae6660fbbafedd07559c6a2e57cd553b34b0065b6550685f6653a98c1cb \ + --hash=sha256:46923b0b5ee7fc0020bef24afe7836cb068f5050ca04caf6b487c513dc1a20b2 \ + --hash=sha256:53e420a3afe22cdcf2a0f4846e377d16e718bc70103d7088a4f7623567ba5fb0 \ + --hash=sha256:5ee4d4ef48036ff6e5cfffb09dd192c7a5027153948d85b8da7ff705065bacc6 \ + --hash=sha256:67dd654b8ca23aed0a8e99010b4c34aca62f4b7fce88f39d452ed7622c94845c \ + --hash=sha256:787ae31ad8a2856fc4e7c095341cccc7209bd657d0e71ad0dc2ea83c4a6fa8af \ + --hash=sha256:86975dca1c773a2c9864f4c52c5a55631038e387b47eaf56210f873887b6c8dc \ + --hash=sha256:87c43e0f13022b998eb9b973b5e97200c8b90823454d4bc06ab33829e09fb9bb \ + --hash=sha256:88cb67cdbc0e483da00af0b2c3cdad4b7c61ceb1ee0f33fe00e09c81e3a6cb75 \ + --hash=sha256:8a375441696e2eda1c43c44ccb66e04d61ceeffcd76e4929e527b7fa401b90fb \ + --hash=sha256:a5c39f217ab3c663dc699c04cbd50c13813e31d917642d459fdcec07555cc553 \ + --hash=sha256:b9fb766bb57b7388745d8bcc53a359b116b8a04c83a2288069809d2b3466c37e \ + --hash=sha256:baa0e6291d91649c6ba4ed4b2f982f9fa165b5bbd50a9e203c416a2797bab3c6 \ + --hash=sha256:baa4dcdbd9ae0a372f2167a207cd98c9f9a1ea1188a8a526431eef2f8116cc8d \ + --hash=sha256:bc09f0ff191e61c2d592a752423c767b4ebb2986daa9ed62908e2b1b9a9ae206 \ + --hash=sha256:bd53ecc9a0f3d87ab847503c2e1552b690362e005ab54e8a48ba97da3924c0dc \ + --hash=sha256:bfd55dfcc2a512316e65f16e503e9e450cab148ef11df4e4e679b5e8253a5281 \ + --hash=sha256:c097078b8031190c934ed0ebfee8cc5f9ba9642e6eb88322b9958b649750f72b \ + --hash=sha256:c0f3fa6200b3108919f8bdabb9a7f87f20e7097ea3c543754cabc7d717d95cf8 \ + --hash=sha256:e678ad6fe52af2c58d2ae3c73dc85524ba8abe637f134bf3564ed07f555c5e79 \ + --hash=sha256:ec7e6b09a6fdded42403182ab6b832b71f4edaf7f37a9a0e371a01db5f0cb45f \ + --hash=sha256:f0ce1b49560b1d2d8a2977e3ba4afb2414fb46b86a1b64056bc4ab929efdafbe \ + --hash=sha256:f38b2e090258d051d68a5b14d1da7203a3c3677321cf32a95a6f4db4dd8b6f26 \ + --hash=sha256:f3df876acd7ec037a3d005b3ab85a7e4110422e4d9c1571d4fc89b0fc41b6816 \ + --hash=sha256:f7089d2dc73179ce5ac255bdf37c236a9f914b264825fdaacaded6990a7fb4c2 watchfiles==0.24.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:01550ccf1d0aed6ea375ef259706af76ad009ef5b0203a3a4cce0f6024f9b68a \ --hash=sha256:01def80eb62bd5db99a798d5e1f5f940ca0a05986dcfae21d833af7a46f7ee22 \ @@ -1907,9 +1713,6 @@ watchfiles==0.24.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:f83df90191d67af5a831da3a33dd7628b02a95450e168785586ed51e6d28943c \ --hash=sha256:fca9433a45f18b7c779d2bae7beeec4f740d28b788b117a48368d95a3233ed83 \ --hash=sha256:fd92bbaa2ecdb7864b7600dcdb6f2f1db6e0346ed425fbd01085be04c63f0b05 -wcwidth==0.2.13 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:3da69048e4540d84af32131829ff948f1e022c1c6bdb8d6102117aac784f6859 \ - --hash=sha256:72ea0c06399eb286d978fdedb6923a9eb47e1c486ce63e9b4e64fc18303972b5 websockets==13.1 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:004280a140f220c812e65f36944a9ca92d766b6cc4560be652a0a3883a79ed8a \ --hash=sha256:035233b7531fb92a76beefcbf479504db8c72eb3bff41da55aecce3a0f729e54 \ @@ -2005,9 +1808,6 @@ wheel==0.44.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:a29c3f2817e95ab89aa4660681ad547c0e9547f20e75b0562fe7723c9a2a9d49 win-unicode-console==0.5 ; platform_system == "Windows" and platform_python_implementation != "PyPy" and python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:d4142d4d56d46f449d6f00536a73625a871cba040f0bc1a2e305a04578f07d1e -xmltodict==0.13.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:341595a488e3e01a85a9d8911d8912fd922ede5fecc4dce437eb4b6c8d037e56 \ - --hash=sha256:aa89e8fd76320154a40d19a0df04a4695fb9dc5ba977cbb68ab3e4eb225e7852 yara-python==4.5.1 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:024c477f182c26265fc447051e09099016e3562ac7f2255e05de2a506dd4d6dc \ --hash=sha256:0324175b06c440eb754b7ff3845b6eb426b5870bbbebbeae32f2e5281fd35860 \ @@ -2092,38 +1892,41 @@ yara-python==4.5.1 ; python_version >= "3.10" and python_version < "4.0" \ zope-event==5.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:2832e95014f4db26c47a13fdaef84cef2f4df37e66b59d8f1f4a8f319a632c26 \ --hash=sha256:bac440d8d9891b4068e2b5a2c5e2c9765a9df762944bda6955f96bb9b91e67cd -zope-interface==7.0.3 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:01e6e58078ad2799130c14a1d34ec89044ada0e1495329d72ee0407b9ae5100d \ - --hash=sha256:064ade95cb54c840647205987c7b557f75d2b2f7d1a84bfab4cf81822ef6e7d1 \ - --hash=sha256:11fa1382c3efb34abf16becff8cb214b0b2e3144057c90611621f2d186b7e1b7 \ - --hash=sha256:1bee1b722077d08721005e8da493ef3adf0b7908e0cd85cc7dc836ac117d6f32 \ - --hash=sha256:1eeeb92cb7d95c45e726e3c1afe7707919370addae7ed14f614e22217a536958 \ - --hash=sha256:21a207c6b2c58def5011768140861a73f5240f4f39800625072ba84e76c9da0b \ - --hash=sha256:2545d6d7aac425d528cd9bf0d9e55fcd47ab7fd15f41a64b1c4bf4c6b24946dc \ - --hash=sha256:2c4316a30e216f51acbd9fb318aa5af2e362b716596d82cbb92f9101c8f8d2e7 \ - --hash=sha256:35062d93bc49bd9b191331c897a96155ffdad10744ab812485b6bad5b588d7e4 \ - --hash=sha256:382d31d1e68877061daaa6499468e9eb38eb7625d4369b1615ac08d3860fe896 \ - --hash=sha256:3aa8fcbb0d3c2be1bfd013a0f0acd636f6ed570c287743ae2bbd467ee967154d \ - --hash=sha256:3d4b91821305c8d8f6e6207639abcbdaf186db682e521af7855d0bea3047c8ca \ - --hash=sha256:3de1d553ce72868b77a7e9d598c9bff6d3816ad2b4cc81c04f9d8914603814f3 \ - --hash=sha256:3fcdc76d0cde1c09c37b7c6b0f8beba2d857d8417b055d4f47df9c34ec518bdd \ - --hash=sha256:5112c530fa8aa2108a3196b9c2f078f5738c1c37cfc716970edc0df0414acda8 \ - --hash=sha256:53d678bb1c3b784edbfb0adeebfeea6bf479f54da082854406a8f295d36f8386 \ - --hash=sha256:6195c3c03fef9f87c0dbee0b3b6451df6e056322463cf35bca9a088e564a3c58 \ - --hash=sha256:6d04b11ea47c9c369d66340dbe51e9031df2a0de97d68f442305ed7625ad6493 \ - --hash=sha256:6dd647fcd765030638577fe6984284e0ebba1a1008244c8a38824be096e37fe3 \ - --hash=sha256:799ef7a444aebbad5a145c3b34bff012b54453cddbde3332d47ca07225792ea4 \ - --hash=sha256:7d92920416f31786bc1b2f34cc4fc4263a35a407425319572cbf96b51e835cd3 \ - --hash=sha256:7e0c151a6c204f3830237c59ee4770cc346868a7a1af6925e5e38650141a7f05 \ - --hash=sha256:84f8794bd59ca7d09d8fce43ae1b571be22f52748169d01a13d3ece8394d8b5b \ - --hash=sha256:95e5913ec718010dc0e7c215d79a9683b4990e7026828eedfda5268e74e73e11 \ - --hash=sha256:9b9369671a20b8d039b8e5a1a33abd12e089e319a3383b4cc0bf5c67bd05fe7b \ - --hash=sha256:ab985c566a99cc5f73bc2741d93f1ed24a2cc9da3890144d37b9582965aff996 \ - --hash=sha256:af94e429f9d57b36e71ef4e6865182090648aada0cb2d397ae2b3f7fc478493a \ - --hash=sha256:c96b3e6b0d4f6ddfec4e947130ec30bd2c7b19db6aa633777e46c8eecf1d6afd \ - --hash=sha256:cd2690d4b08ec9eaf47a85914fe513062b20da78d10d6d789a792c0b20307fb1 \ - --hash=sha256:d3b7ce6d46fb0e60897d62d1ff370790ce50a57d40a651db91a3dde74f73b738 \ - --hash=sha256:d976fa7b5faf5396eb18ce6c132c98e05504b52b60784e3401f4ef0b2e66709b \ - --hash=sha256:db6237e8fa91ea4f34d7e2d16d74741187e9105a63bbb5686c61fea04cdbacca \ - --hash=sha256:ecd32f30f40bfd8511b17666895831a51b532e93fc106bfa97f366589d3e4e0e \ - --hash=sha256:f418c88f09c3ba159b95a9d1cfcdbe58f208443abb1f3109f4b9b12fd60b187c +zope-interface==7.1.1 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:0de23bcb93401994ea00bc5c677ef06d420340ac0a4e9c10d80e047b9ce5af3f \ + --hash=sha256:179ad46ece518c9084cb272e4a69d266b659f7f8f48e51706746c2d8a426433e \ + --hash=sha256:190eeec67e023d5aac54d183fa145db0b898664234234ac54643a441da434616 \ + --hash=sha256:1a2ed0852c25950cf430067f058f8d98df6288502ac313861d9803fe7691a9b3 \ + --hash=sha256:1c4e1b4c06d9abd1037c088dae1566c85f344a3e6ae4350744c3f7f7259d9c67 \ + --hash=sha256:1d0e23c6b746eb8ce04573cc47bcac60961ac138885d207bd6f57e27a1431ae8 \ + --hash=sha256:2317e1d4dba68203a5227ea3057f9078ec9376275f9700086b8f0ffc0b358e1b \ + --hash=sha256:2d553e02b68c0ea5a226855f02edbc9eefd99f6a8886fa9f9bdf999d77f46585 \ + --hash=sha256:3603ef82a9920bd0bfb505423cb7e937498ad971ad5a6141841e8f76d2fd5446 \ + --hash=sha256:3defc925c4b22ac1272d544a49c6ba04c3eefcce3200319ee1be03d9270306dd \ + --hash=sha256:3e59f175e868f856a77c0a77ba001385c377df2104fdbda6b9f99456a01e102a \ + --hash=sha256:4284d664ef0ff7b709836d4de7b13d80873dc5faeffc073abdb280058bfac5e3 \ + --hash=sha256:55c373becbd36a44d0c9be1d5271422fdaa8562d158fb44b4192297b3c67096c \ + --hash=sha256:5836b8fb044c6e75ba34dfaabc602493019eadfa0faf6ff25f4c4c356a71a853 \ + --hash=sha256:5cdb7e7e5524b76d3ec037c1d81a9e2c7457b240fd4cb0a2476b65c3a5a6c81f \ + --hash=sha256:6650bd56ef350d37c8baccfd3ee8a0483ed6f8666e641e4b9ae1a1827b79f9e5 \ + --hash=sha256:7395f13533318f150ee72adb55b29284b16e73b6d5f02ab21f173b3e83f242b8 \ + --hash=sha256:7720322763aceb5e0a7cadcc38c67b839efe599f0887cbf6c003c55b1458c501 \ + --hash=sha256:7cd5e3d910ac87652a09f6e5db8e41bc3b49cf08ddd2d73d30afc644801492cd \ + --hash=sha256:81744a7e61b598ebcf4722ac56a7a4f50502432b5b4dc7eb29075a89cf82d029 \ + --hash=sha256:84e87eba6b77a3af187bae82d8de1a7c208c2a04ec9f6bd444fd091b811ad92e \ + --hash=sha256:8d0fe45be57b5219aa4b96e846631c04615d5ef068146de5a02ccd15c185321f \ + --hash=sha256:9595e478047ce752b35cfa221d7601a5283ccdaab40422e0dc1d4a334c70f580 \ + --hash=sha256:99c14f0727c978639139e6cad7a60e82b7720922678d75aacb90cf4ef74a068c \ + --hash=sha256:9b1eed7670d564f1025d7cda89f99f216c30210e42e95de466135be0b4a499d9 \ + --hash=sha256:9fad9bd5502221ab179f13ea251cb30eef7cf65023156967f86673aff54b53a0 \ + --hash=sha256:ad339509dcfbbc99bf8e147db6686249c4032f26586699ec4c82f6e5909c9fe2 \ + --hash=sha256:bcbeb44fc16e0078b3b68a95e43f821ae34dcbf976dde6985141838a5f23dd3d \ + --hash=sha256:c8e7b05dc6315a193cceaec071cc3cf1c180cea28808ccded0b1283f1c38ba73 \ + --hash=sha256:ca95594d936ee349620900be5b46c0122a1ff6ce42d7d5cb2cf09dc84071ef16 \ + --hash=sha256:d029fac6a80edae80f79c37e5e3abfa92968fe921886139b3ee470a1b177321a \ + --hash=sha256:d17e7fc814eaab93409b80819fd6d30342844345c27f3bc3c4b43c2425a8d267 \ + --hash=sha256:d6821ef9870f32154da873fcde439274f99814ea452dd16b99fa0b66345c4b6b \ + --hash=sha256:e6503534b52bb1720ace9366ee30838a58a3413d3e197512f3338c8f34b5d89d \ + --hash=sha256:ed1df8cc01dd1e3970666a7370b8bfc7457371c58ba88c57bd5bca17ab198053 \ + --hash=sha256:f1d52d052355e0c5c89e0630dd2ff7c0b823fd5f56286a663e92444761b35e25 \ + --hash=sha256:f85b290e5b8b11814efb0d004d8ce6c9a483c35c462e8d9bf84abb93e79fa770 From 5105285c719c8ee9212e9f9155548a0913ae595f Mon Sep 17 00:00:00 2001 From: doomedraven Date: Sat, 2 Nov 2024 15:40:55 +0100 Subject: [PATCH 033/121] sync --- changelog.md | 1 + lib/cuckoo/common/cape_utils.py | 17 +++++++++-------- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/changelog.md b/changelog.md index 48e6f7c26ed..83d8f84ae24 100644 --- a/changelog.md +++ b/changelog.md @@ -5,6 +5,7 @@ * All = core and community * Exclude parsers. Allows to not load some particular parsers. `exclude_parsers=["name1", "name2"]` * Your custom parsers from `custom/parsers/` will still load and overwrite cape carser if name matches. +* __Action required!__ `cd /opt/CAPEv2 && poetry install` ### [04.10.2024] * Monitor update: Add GetClassObject hook to handle UAC bypass technique using CMSTPLUA COM object diff --git a/lib/cuckoo/common/cape_utils.py b/lib/cuckoo/common/cape_utils.py index 6141ed254a6..ac08c34a33c 100644 --- a/lib/cuckoo/common/cape_utils.py +++ b/lib/cuckoo/common/cape_utils.py @@ -18,9 +18,14 @@ except ImportError: HAVE_PYDEEP = False - +HAS_MWCP = False +HAS_MALWARECONFIGS = False +HAVE_CAPE_EXTRACTORS = False with suppress(ImportError): from cape_parsers import load_cape_parsers, load_mwcp_parsers, load_malwareconfig_parsers # load_malduck_parsers + HAS_MWCP = True + HAS_MALWARECONFIGS = True + HAVE_CAPE_EXTRACTORS = True cape_malware_parsers = {} @@ -48,14 +53,11 @@ print("Missed pefile library. Install it with: pip3 install pefile") HAVE_PEFILE = False -# ToDo check if enabled -HAS_MWCP = False -if process_cfg.mwcp.enabled: +if process_cfg.mwcp.enabled and HAS_MWCP: malware_parsers, mwcp = load_mwcp_parsers() HAS_MWCP = bool(malware_parsers) -HAS_MALWARECONFIGS = False -if not process_cfg.ratdecoders.enabled: +if not process_cfg.ratdecoders.enabled and HAS_MALWARECONFIGS: HAS_MALWARECONFIGS, __decoders__, fileparser = load_malwareconfig_parsers() HAVE_MALDUCK = False @@ -81,8 +83,7 @@ except ImportError: log.info("Missed MalDuck -> pip3 install git+https://github.com/CERT-Polska/malduck/") -HAVE_CAPE_EXTRACTORS = False -if process_cfg.CAPE_extractors.enabled: +if process_cfg.CAPE_extractors.enabled and HAVE_CAPE_EXTRACTORS: from lib.cuckoo.common.load_extra_modules import cape_load_decoders cape_malware_parsers = load_cape_parsers() if cape_malware_parsers: From 2815fb1dfcea5772065097c8464a2c765bae2a4d Mon Sep 17 00:00:00 2001 From: doomedraven Date: Sun, 3 Nov 2024 20:16:27 +0100 Subject: [PATCH 034/121] load custom cape parsers --- lib/cuckoo/common/cape_utils.py | 13 +++++++------ lib/cuckoo/common/load_extra_modules.py | 2 +- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/lib/cuckoo/common/cape_utils.py b/lib/cuckoo/common/cape_utils.py index ac08c34a33c..7f8a1c28c6a 100644 --- a/lib/cuckoo/common/cape_utils.py +++ b/lib/cuckoo/common/cape_utils.py @@ -83,15 +83,16 @@ except ImportError: log.info("Missed MalDuck -> pip3 install git+https://github.com/CERT-Polska/malduck/") -if process_cfg.CAPE_extractors.enabled and HAVE_CAPE_EXTRACTORS: - from lib.cuckoo.common.load_extra_modules import cape_load_decoders - cape_malware_parsers = load_cape_parsers() +if process_cfg.CAPE_extractors.enabled: + from lib.cuckoo.common.load_extra_modules import cape_load_custom_decoders + cape_malware_parsers = {} + if HAVE_CAPE_EXTRACTORS: + cape_malware_parsers = load_cape_parsers() + # Custom overwrites core + cape_malware_parsers.update(cape_load_custom_decoders(CUCKOO_ROOT)) if cape_malware_parsers: HAVE_CAPE_EXTRACTORS = True assert "test cape" in cape_malware_parsers - # Custom overwrites core - cape_malware_parsers.update(cape_load_decoders(CUCKOO_ROOT)) - suppress_parsing_list = ["Cerber", "Emotet_Payload", "Ursnif", "QakBot"] diff --git a/lib/cuckoo/common/load_extra_modules.py b/lib/cuckoo/common/load_extra_modules.py index 35ce80f423e..1d38f2ca385 100644 --- a/lib/cuckoo/common/load_extra_modules.py +++ b/lib/cuckoo/common/load_extra_modules.py @@ -34,7 +34,7 @@ def ratdecodedr_load_decoders(path: str): return dec_modules -def cape_load_decoders(CUCKOO_ROOT: str): +def cape_load_custom_decoders(CUCKOO_ROOT: str): cape_modules = {} cape_decoders = os.path.join(CUCKOO_ROOT, "modules", "processing", "parsers", "CAPE") From fbe5fdf83ddb822ec4b3060e8cfcd04ae8842177 Mon Sep 17 00:00:00 2001 From: doomedraven Date: Sun, 3 Nov 2024 20:24:27 +0100 Subject: [PATCH 035/121] Update cape_utils.py --- lib/cuckoo/common/cape_utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/cuckoo/common/cape_utils.py b/lib/cuckoo/common/cape_utils.py index 7f8a1c28c6a..f9f85438a9a 100644 --- a/lib/cuckoo/common/cape_utils.py +++ b/lib/cuckoo/common/cape_utils.py @@ -50,7 +50,7 @@ HAVE_PEFILE = True except ImportError: - print("Missed pefile library. Install it with: pip3 install pefile") + print("Missed pefile library. Install it with: poetry install") HAVE_PEFILE = False if process_cfg.mwcp.enabled and HAS_MWCP: From 619c145dcee6fc8ca482bcb4d95a4a373f0e62b9 Mon Sep 17 00:00:00 2001 From: GitHub Actions Date: Mon, 4 Nov 2024 07:03:59 +0000 Subject: [PATCH 036/121] style: Automatic code formatting --- lib/cuckoo/common/cape_utils.py | 6 ++++-- lib/cuckoo/core/database.py | 11 +++++------ lib/cuckoo/core/scheduler.py | 2 +- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/lib/cuckoo/common/cape_utils.py b/lib/cuckoo/common/cape_utils.py index f9f85438a9a..31f1974645e 100644 --- a/lib/cuckoo/common/cape_utils.py +++ b/lib/cuckoo/common/cape_utils.py @@ -2,8 +2,8 @@ import logging import tempfile from collections.abc import Iterable, Mapping -from pathlib import Path from contextlib import suppress +from pathlib import Path from lib.cuckoo.common.config import Config from lib.cuckoo.common.constants import CUCKOO_ROOT @@ -22,7 +22,8 @@ HAS_MALWARECONFIGS = False HAVE_CAPE_EXTRACTORS = False with suppress(ImportError): - from cape_parsers import load_cape_parsers, load_mwcp_parsers, load_malwareconfig_parsers # load_malduck_parsers + from cape_parsers import load_cape_parsers, load_malwareconfig_parsers, load_mwcp_parsers # load_malduck_parsers + HAS_MWCP = True HAS_MALWARECONFIGS = True HAVE_CAPE_EXTRACTORS = True @@ -85,6 +86,7 @@ if process_cfg.CAPE_extractors.enabled: from lib.cuckoo.common.load_extra_modules import cape_load_custom_decoders + cape_malware_parsers = {} if HAVE_CAPE_EXTRACTORS: cape_malware_parsers = load_cape_parsers() diff --git a/lib/cuckoo/core/database.py b/lib/cuckoo/core/database.py index 7f88487641f..a38322da31d 100644 --- a/lib/cuckoo/core/database.py +++ b/lib/cuckoo/core/database.py @@ -170,8 +170,8 @@ tasks_tags = Table( "tasks_tags", Base.metadata, - Column("task_id", Integer, ForeignKey("tasks.id", ondelete='cascade')), - Column("tag_id", Integer, ForeignKey("tags.id", ondelete='cascade')), + Column("task_id", Integer, ForeignKey("tasks.id", ondelete="cascade")), + Column("tag_id", Integer, ForeignKey("tags.id", ondelete="cascade")), ) @@ -269,7 +269,7 @@ class Guest(Base): manager = Column(String(255), nullable=False) started_on = Column(DateTime(timezone=False), default=datetime.now, nullable=False) shutdown_on = Column(DateTime(timezone=False), nullable=True) - task_id = Column(Integer, ForeignKey("tasks.id", ondelete='cascade'), nullable=False, unique=True) + task_id = Column(Integer, ForeignKey("tasks.id", ondelete="cascade"), nullable=False, unique=True) def __repr__(self): return f"" @@ -2093,8 +2093,7 @@ def list_tasks( return tasks def check_tasks_timeout(self, timeout): - """Find tasks which were added_on more than timeout ago and clean - """ + """Find tasks which were added_on more than timeout ago and clean""" tasks: List[Task] = [] ids_to_delete = [] if timeout == 0: @@ -2102,7 +2101,7 @@ def check_tasks_timeout(self, timeout): search = self.session.query(Task).filter(Task.status == TASK_PENDING).order_by(Task.added_on.desc()) tasks = search.all() for task in tasks: - if task.added_on + timedelta(seconds = timeout) < datetime.now(): + if task.added_on + timedelta(seconds=timeout) < datetime.now(): ids_to_delete.append(task.id) if len(ids_to_delete) > 0: self.session.query(Task).filter(Task.id.in_(ids_to_delete)).delete(synchronize_session=False) diff --git a/lib/cuckoo/core/scheduler.py b/lib/cuckoo/core/scheduler.py index 3831c4a55b3..45d6b8dc506 100644 --- a/lib/cuckoo/core/scheduler.py +++ b/lib/cuckoo/core/scheduler.py @@ -102,7 +102,7 @@ def do_main_loop_work(self, error_queue: queue.Queue) -> SchedulerCycleDelay: if self.cfg.cuckoo.get("task_timeout", False): if self.next_timeout_time < time.time(): - self.next_timeout_time = time.time() + self.cfg.cuckoo.get("task_timeout_scan_interval", 30) + self.next_timeout_time = time.time() + self.cfg.cuckoo.get("task_timeout_scan_interval", 30) with self.db.session.begin(): self.db.check_tasks_timeout(self.cfg.cuckoo.get("task_pending_timeout", 0)) From 2a10e7bb72d2861c97b27534d879e9fb29a04f13 Mon Sep 17 00:00:00 2001 From: doomedraven Date: Mon, 4 Nov 2024 11:09:16 +0100 Subject: [PATCH 037/121] Update cape_utils.py --- lib/cuckoo/common/cape_utils.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/cuckoo/common/cape_utils.py b/lib/cuckoo/common/cape_utils.py index 31f1974645e..f55acec0ca9 100644 --- a/lib/cuckoo/common/cape_utils.py +++ b/lib/cuckoo/common/cape_utils.py @@ -62,6 +62,7 @@ HAS_MALWARECONFIGS, __decoders__, fileparser = load_malwareconfig_parsers() HAVE_MALDUCK = False +""" # ToDo move if process_cfg.malduck.enabled: try: @@ -83,6 +84,7 @@ assert "test_malduck" in malduck_modules_names except ImportError: log.info("Missed MalDuck -> pip3 install git+https://github.com/CERT-Polska/malduck/") +""" if process_cfg.CAPE_extractors.enabled: from lib.cuckoo.common.load_extra_modules import cape_load_custom_decoders @@ -261,7 +263,7 @@ def static_config_parsers(cape_name, file_path, file_data): if cape_config.get(cape_name) == {}: return {} - + """ elif HAVE_MALDUCK and not parser_loaded and cape_name.lower() in malduck_modules_names: log.debug("Running Malduck on %s", file_path) if not File.yara_initialized: @@ -285,7 +287,7 @@ def static_config_parsers(cape_name, file_path, file_data): if not cape_config[cape_name]: return {} - + """ return cape_config From b21cdbf9dc430da87abccc6782529f78bea94e28 Mon Sep 17 00:00:00 2001 From: doomedraven Date: Mon, 4 Nov 2024 12:11:33 +0100 Subject: [PATCH 038/121] fix --- lib/cuckoo/common/cape_utils.py | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/lib/cuckoo/common/cape_utils.py b/lib/cuckoo/common/cape_utils.py index f55acec0ca9..6fffbe92cb6 100644 --- a/lib/cuckoo/common/cape_utils.py +++ b/lib/cuckoo/common/cape_utils.py @@ -28,6 +28,8 @@ HAS_MALWARECONFIGS = True HAVE_CAPE_EXTRACTORS = True +mwcp_decoders = {} +rat_decoders = {} cape_malware_parsers = {} # Config variables @@ -55,11 +57,11 @@ HAVE_PEFILE = False if process_cfg.mwcp.enabled and HAS_MWCP: - malware_parsers, mwcp = load_mwcp_parsers() - HAS_MWCP = bool(malware_parsers) + mwcp_decoders, mwcp = load_mwcp_parsers() + HAS_MWCP = bool(mwcp_decoders) if not process_cfg.ratdecoders.enabled and HAS_MALWARECONFIGS: - HAS_MALWARECONFIGS, __decoders__, fileparser = load_malwareconfig_parsers() + HAS_MALWARECONFIGS, rat_decoders, fileparser = load_malwareconfig_parsers() HAVE_MALDUCK = False """ @@ -190,10 +192,10 @@ def static_config_parsers(cape_name, file_path, file_data): log.error("CAPE: parsing error on %s with %s: %s", file_path, cape_name, e, exc_info=True) # DC3-MWCP - if HAS_MWCP and not parser_loaded and cape_name and cape_name in malware_parsers: + if HAS_MWCP and not parser_loaded and cape_name and cape_name in mwcp_decoders: log.debug("Running MWCP on %s", file_path) try: - report = mwcp.run(malware_parsers[cape_name], data=file_data) + report = mwcp.run(mwcp_decoders[cape_name], data=file_data) reportmeta = report.as_dict_legacy() if not report.errors: parser_loaded = True @@ -225,16 +227,16 @@ def static_config_parsers(cape_name, file_path, file_data): str(e), ) - elif HAS_MALWARECONFIGS and not parser_loaded and cape_name in __decoders__: + elif HAS_MALWARECONFIGS and not parser_loaded and cape_name in rat_decoders: log.debug("Running Malwareconfigs on %s", file_path) try: module = False file_info = fileparser.FileParser(rawdata=file_data) # Detects name by embed yara - if file_info.malware_name in __decoders__: - module = __decoders__[file_info.malware_name]["obj"]() - elif cape_name in __decoders__: - module = __decoders__[cape_name]["obj"]() + if file_info.malware_name in rat_decoders: + module = rat_decoders[file_info.malware_name]["obj"]() + elif cape_name in rat_decoders: + module = rat_decoders[cape_name]["obj"]() else: log.warning("%s: %s wasn't matched by plugin's yara", file_path, cape_name) From e557c2b2d69e26a7ee901941ea6b831d6bd169f9 Mon Sep 17 00:00:00 2001 From: doomedraven Date: Mon, 4 Nov 2024 12:17:42 +0100 Subject: [PATCH 039/121] Update cape_utils.py --- lib/cuckoo/common/cape_utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/cuckoo/common/cape_utils.py b/lib/cuckoo/common/cape_utils.py index 6fffbe92cb6..931420a8b24 100644 --- a/lib/cuckoo/common/cape_utils.py +++ b/lib/cuckoo/common/cape_utils.py @@ -1,6 +1,6 @@ import hashlib import logging -import tempfile +# import tempfile from collections.abc import Iterable, Mapping from contextlib import suppress from pathlib import Path From 8cd7cb4572ee8ff7dc720977e4e92c402465f4c3 Mon Sep 17 00:00:00 2001 From: GitHub Actions Date: Mon, 4 Nov 2024 11:18:38 +0000 Subject: [PATCH 040/121] style: Automatic code formatting --- lib/cuckoo/common/cape_utils.py | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/cuckoo/common/cape_utils.py b/lib/cuckoo/common/cape_utils.py index 931420a8b24..04cc5522e4b 100644 --- a/lib/cuckoo/common/cape_utils.py +++ b/lib/cuckoo/common/cape_utils.py @@ -1,5 +1,6 @@ import hashlib import logging + # import tempfile from collections.abc import Iterable, Mapping from contextlib import suppress From b9d4bee197cd57bbb0c10cb8d1c37d86f40ceea2 Mon Sep 17 00:00:00 2001 From: doomedraven Date: Mon, 4 Nov 2024 12:57:43 +0100 Subject: [PATCH 041/121] Update objects.py --- lib/cuckoo/common/objects.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/cuckoo/common/objects.py b/lib/cuckoo/common/objects.py index d8a3814013f..16c957384b3 100644 --- a/lib/cuckoo/common/objects.py +++ b/lib/cuckoo/common/objects.py @@ -623,7 +623,10 @@ def get_cape_name_from_cape_type(cls, cape_type: str) -> str: """Return the part of the cape_type (e.g. "SocGholish Payload") preceding " Payload", " Config", " Loader", or " Strings" """ - return cls.cape_name_regex.sub("", cape_type) + if bool(cls.cape_name_regex.search(cape_type)): + return cls.cape_name_regex.sub("", cape_type) + else: + return "" def get_tlsh(self): """ From 377e50ca85ca9f496eadb9e49d35a214ca2615e1 Mon Sep 17 00:00:00 2001 From: doomedraven Date: Mon, 4 Nov 2024 13:43:09 +0100 Subject: [PATCH 042/121] Update cape_utils.py --- lib/cuckoo/common/cape_utils.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/cuckoo/common/cape_utils.py b/lib/cuckoo/common/cape_utils.py index 04cc5522e4b..75ca6fca0c6 100644 --- a/lib/cuckoo/common/cape_utils.py +++ b/lib/cuckoo/common/cape_utils.py @@ -287,10 +287,9 @@ def static_config_parsers(cape_name, file_path, file_data): if tmp_config: for key, value in tmp_config[0].items(): cape_config[cape_name].update({key: [value]}) - + """ if not cape_config[cape_name]: return {} - """ return cape_config From 4f0311a134fc10667ade905c397b9b14ed1b1835 Mon Sep 17 00:00:00 2001 From: cccs-mog <117194682+cccs-mog@users.noreply.github.com> Date: Mon, 4 Nov 2024 14:13:45 -0500 Subject: [PATCH 043/121] Update package for rdp package --- analyzer/windows/lib/core/packages.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/analyzer/windows/lib/core/packages.py b/analyzer/windows/lib/core/packages.py index c41ebe4ba6f..2fbf6ac22e0 100644 --- a/analyzer/windows/lib/core/packages.py +++ b/analyzer/windows/lib/core/packages.py @@ -147,5 +147,7 @@ def choose_package(file_type, file_name, exports, target): return "autoit" elif file_name.endswith(("cmd", "bat")) or b"@echo off" in file_content: return "batch" + elif file_name.endswith(".rdp"): + return "rdp" else: return "generic" From 223a36da4f6c63936d90f35e6e4e4ffae9da940a Mon Sep 17 00:00:00 2001 From: cccs-mog <117194682+cccs-mog@users.noreply.github.com> Date: Mon, 4 Nov 2024 14:26:09 -0500 Subject: [PATCH 044/121] Update rdp.py --- analyzer/windows/modules/packages/rdp.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/analyzer/windows/modules/packages/rdp.py b/analyzer/windows/modules/packages/rdp.py index 016df77bbf4..f6124a67f98 100644 --- a/analyzer/windows/modules/packages/rdp.py +++ b/analyzer/windows/modules/packages/rdp.py @@ -2,7 +2,7 @@ from lib.common.common import check_file_extension -class Exe(Package): +class RDP(Package): """RDP analysis package.""" PATHS = [ From 67eb5ca926484d701e539a8a761123f9f9d68215 Mon Sep 17 00:00:00 2001 From: doomedraven Date: Tue, 5 Nov 2024 11:01:31 +0100 Subject: [PATCH 045/121] parse_rdp --- .../common/integrations/file_extra_info.py | 4 +- lib/cuckoo/common/integrations/parse_rdp.py | 154 ++++++++++++++++++ 2 files changed, 157 insertions(+), 1 deletion(-) create mode 100644 lib/cuckoo/common/integrations/parse_rdp.py diff --git a/lib/cuckoo/common/integrations/file_extra_info.py b/lib/cuckoo/common/integrations/file_extra_info.py index b49d5d31415..5595a662ae9 100644 --- a/lib/cuckoo/common/integrations/file_extra_info.py +++ b/lib/cuckoo/common/integrations/file_extra_info.py @@ -29,6 +29,7 @@ from lib.cuckoo.common.integrations.parse_pdf import PDF from lib.cuckoo.common.integrations.parse_pe import HAVE_PEFILE, PortableExecutable from lib.cuckoo.common.integrations.parse_wsf import WindowsScriptFile # EncodedScriptFile +from lib.cuckoo.common.integration.parse_rdp import parse_rdp_file # from lib.cuckoo.common.integrations.parse_elf import ELF from lib.cuckoo.common.load_extra_modules import file_extra_info_load_modules @@ -205,7 +206,8 @@ def static_file_info( log.error("procyon_path specified in processing.conf but the file does not exist") else: data_dictionary["java"] = Java(file_path, selfextract_conf.procyon.binary).run() - + elif file_path.endswith(".rdp"): + data_dictionary["rdp"] = parse_rdp_file(file_path) # It's possible to fool libmagic into thinking our 2007+ file is a zip. # So until we have static analysis for zip files, we can use oleid to fail us out silently, # yeilding no static analysis results for actual zip files. diff --git a/lib/cuckoo/common/integrations/parse_rdp.py b/lib/cuckoo/common/integrations/parse_rdp.py new file mode 100644 index 00000000000..bb655a3b579 --- /dev/null +++ b/lib/cuckoo/common/integrations/parse_rdp.py @@ -0,0 +1,154 @@ +# From https://github.com/wmetcalf/rdp_holiday + +import json +import argparse +import base64 +from struct import unpack + +import sys +from hashlib import sha1, sha256 +from cryptography.hazmat.primitives import hashes +from cryptography.hazmat.primitives.serialization import pkcs7 + +try: + import re2 as re +except ImportError: + import re + +property_patterns = { + "alternate_full_address": re.compile(r"alternate\s+full\s+address\s*:\s*s\s*:\s*(.*)", re.I), + "alternate_shell": re.compile(r"alternate\s+shell\s*:\s*s\s*:\s*(.*)", re.I), + "authentication_level": re.compile(r"authentication\s+level\s*:\s*i\s*:\s*(\d+)", re.I), + "autoreconnection_enabled": re.compile(r"autoreconnection\s*enabled\s*:\s*i\s*:\s*(\d+)", re.I), + "audiocapturemode": re.compile(r"audiocapturemode\s*:\s*i\s*:\s*(\d+)", re.I), + "audiomode": re.compile(r"audiomode\s*:\s*i\s*:\s*(\d+)", re.I), + "bandwidthautodetect": re.compile(r"bandwidthautodetect\s*:\s*i\s*:\s*(\d+)", re.I), + "camerastoredirect": re.compile(r"camerastoredirect\s*:\s*s\s*:\s*(.*)", re.I), + "compression": re.compile(r"compression\s*:\s*i\s*:\s*(\d+)", re.I), + "disableconnectionsharing": re.compile(r"disableconnectionsharing\s*:\s*i\s*:\s*(\d+)", re.I), + "drivestoredirect": re.compile(r"drivestoredirect\s*:\s*s\s*:\s*(.*)", re.I), + "enablecredsspsupport": re.compile(r"enablecredsspsupport\s*:\s*i\s*:\s*(\d+)", re.I), + "enablerdsaadauth": re.compile(r"enablerdsaadauth\s*:\s*i\s*:\s*(\d+)", re.I), + "full_address": re.compile(r"full\s+address\s*:\s*s\s*:\s*(.*)", re.I), + "gatewaycredentialssource": re.compile(r"gatewaycredentialssource\s*:\s*i\s*:\s*(\d+)", re.I), + "gatewayhostname": re.compile(r"gatewayhostname\s*:\s*s\s*:\s*(.*)", re.I), + "gatewayprofileusagemethod": re.compile(r"gatewayprofileusagemethod\s*:\s*i\s*:\s*(\d+)", re.I), + "gatewayusagemethod": re.compile(r"gatewayusagemethod\s*:\s*i\s*:\s*(\d+)", re.I), + "keyboardhook": re.compile(r"keyboardhook\s*:\s*i\s*:\s*(\d+)", re.I), + "networkautodetect": re.compile(r"networkautodetect\s*:\s*i\s*:\s*(\d+)", re.I), + "promptcredentialonce": re.compile(r"promptcredentialonce\s*:\s*i\s*:\s*(\d+)", re.I), + "redirectclipboard": re.compile(r"redirectclipboard\s*:\s*i\s*:\s*(\d+)", re.I), + "redirectcomports": re.compile(r"redirectcomports\s*:\s*i\s*:\s*(\d+)", re.I), + "redirectlocation": re.compile(r"redirectlocation\s*:\s*i\s*:\s*(\d+)", re.I), + "redirectprinters": re.compile(r"redirectprinters\s*:\s*i\s*:\s*(\d+)", re.I), + "redirectsmartcards": re.compile(r"redirectsmartcards\s*:\s*i\s*:\s*(\d+)", re.I), + "redirectwebauthn": re.compile(r"redirectwebauthn\s*:\s*i\s*:\s*(\d+)", re.I), + "screen_mode_id": re.compile(r"screen mode id\s*:\s*i\s*:\s*(\d+)", re.I), + "usbdevicestoredirect": re.compile(r"usbdevicestoredirect\s*:\s*s\s*:\s*(.*)", re.I), + "videoplaybackmode": re.compile(r"videoplaybackmode\s*:\s*i\s*:\s*(\d+)", re.I), + "remoteapplicationcmdline": re.compile(r"remoteapplicationcmdline\s*:\s*s\s*:\s*(.*)", re.I), + "remoteapplicationexpandcmdline": re.compile(r"remoteapplicationexpandcmdline\s*:\s*i\s*:\s*(\d+)", re.I), + "remoteapplicationexpandworkingdir": re.compile(r"remoteapplicationexpandworkingdir\s*:\s*i\s*:\s*(\d+)", re.I), + "remoteapplicationfile": re.compile(r"remoteapplicationfile\s*:\s*s\s*:\s*(.*)", re.I), + "remoteapplicationicon": re.compile(r"remoteapplicationicon\s*:\s*s\s*:\s*(.*)", re.I), + "remoteapplicationmode": re.compile(r"remoteapplicationmode\s*:\s*i\s*:\s*(\d+)", re.I), + "remoteapplicationname": re.compile(r"remoteapplicationname\s*:\s*s\s*:\s*(.*)", re.I), + "remoteapplicationprogram": re.compile(r"remoteapplicationprogram\s*:\s*s\s*:\s*(.*)", re.I), + "devicestoredirect": re.compile(r"devicestoredirect\s*:\s*s\s*:\s*(.*)", re.I), + "signature": re.compile(r"signature\s*:\s*s\s*:\s*([A-Za-z0-9+/=\s]+)", re.I), + "signscope": re.compile(r"signscope\s*:\s*s\s*:\s*(.*)", re.I), +} + +def parse_rdp_file(file_path): + rdp_properties = {} + + try: + content = "" + encoding = "utf-8" + with open(file_path, "rb") as f: + raw = f.read(4) + if raw.startswith(b"\xff\xfe\x00\x00"): + encoding = "utf-32-le" + elif raw.startswith(b"\x00\x00\xfe\xff"): + encoding = "utf-32-be" + elif raw.startswith(b"\xfe\xff"): + encoding = "utf-16-be" + elif raw.startswith(b"\xff\xfe"): + encoding = "utf-16-le" + elif raw.startswith(b"\xef\xbb\xbf"): + encoding = "utf-8-sig" + + with open(file_path, "r", encoding=encoding, errors="ignore") as f: + content = f.read() + if content and re.search(r"full\s+address\s*:\s*s\s*:", content, re.I): + for line in content.splitlines(): + for prop, pattern in property_patterns.items(): + match = pattern.search(line) + if match: + value = match.group(1).strip() + if value != "": + rdp_properties[prop] = value + else: + print("full_address is a required field... what sort of nonsense are you trying to feed me?") + return rdp_properties + if "full_address" not in rdp_properties: + print("full_address is a required field but is not in parsed Properties what sort of nonsense are you trying to feed me?") + return rdp_properties + + if "signature" in rdp_properties: + signature_base64 = rdp_properties["signature"] + signature_bytes = base64.b64decode(signature_base64.replace("\n", "").replace("\r", "")) + + size_bytes = signature_bytes[8:12] + data_size = unpack(" Date: Tue, 5 Nov 2024 11:03:51 +0100 Subject: [PATCH 046/121] parse_rdp --- lib/cuckoo/common/integrations/parse_rdp.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/cuckoo/common/integrations/parse_rdp.py b/lib/cuckoo/common/integrations/parse_rdp.py index bb655a3b579..a4231b69c12 100644 --- a/lib/cuckoo/common/integrations/parse_rdp.py +++ b/lib/cuckoo/common/integrations/parse_rdp.py @@ -146,7 +146,7 @@ def main(): with open(args.output, "w") as outfile: outfile.write(output) except Exception as e: - print("it went pear shaped..") + print("it went pear shaped.. %s", str(e)) sys.exit(1) From c5b8437f7559cad304b9e458c844b19187cbf941 Mon Sep 17 00:00:00 2001 From: doomedraven Date: Tue, 5 Nov 2024 11:06:39 +0100 Subject: [PATCH 047/121] parse_rdp --- lib/cuckoo/common/integrations/file_extra_info.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/cuckoo/common/integrations/file_extra_info.py b/lib/cuckoo/common/integrations/file_extra_info.py index 5595a662ae9..8e61483e948 100644 --- a/lib/cuckoo/common/integrations/file_extra_info.py +++ b/lib/cuckoo/common/integrations/file_extra_info.py @@ -29,7 +29,7 @@ from lib.cuckoo.common.integrations.parse_pdf import PDF from lib.cuckoo.common.integrations.parse_pe import HAVE_PEFILE, PortableExecutable from lib.cuckoo.common.integrations.parse_wsf import WindowsScriptFile # EncodedScriptFile -from lib.cuckoo.common.integration.parse_rdp import parse_rdp_file +from lib.cuckoo.common.integrations.parse_rdp import parse_rdp_file # from lib.cuckoo.common.integrations.parse_elf import ELF from lib.cuckoo.common.load_extra_modules import file_extra_info_load_modules From 217cd32d274ee4a15d61718e4189ff9c251581c6 Mon Sep 17 00:00:00 2001 From: GitHub Actions Date: Tue, 5 Nov 2024 10:42:48 +0000 Subject: [PATCH 048/121] style: Automatic code formatting --- lib/cuckoo/common/integrations/file_extra_info.py | 2 +- lib/cuckoo/common/integrations/parse_rdp.py | 11 +++++++---- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/lib/cuckoo/common/integrations/file_extra_info.py b/lib/cuckoo/common/integrations/file_extra_info.py index 8e61483e948..f77541e4bc2 100644 --- a/lib/cuckoo/common/integrations/file_extra_info.py +++ b/lib/cuckoo/common/integrations/file_extra_info.py @@ -28,8 +28,8 @@ from lib.cuckoo.common.integrations.parse_office import HAVE_OLETOOLS, Office from lib.cuckoo.common.integrations.parse_pdf import PDF from lib.cuckoo.common.integrations.parse_pe import HAVE_PEFILE, PortableExecutable -from lib.cuckoo.common.integrations.parse_wsf import WindowsScriptFile # EncodedScriptFile from lib.cuckoo.common.integrations.parse_rdp import parse_rdp_file +from lib.cuckoo.common.integrations.parse_wsf import WindowsScriptFile # EncodedScriptFile # from lib.cuckoo.common.integrations.parse_elf import ELF from lib.cuckoo.common.load_extra_modules import file_extra_info_load_modules diff --git a/lib/cuckoo/common/integrations/parse_rdp.py b/lib/cuckoo/common/integrations/parse_rdp.py index a4231b69c12..82b04ea6142 100644 --- a/lib/cuckoo/common/integrations/parse_rdp.py +++ b/lib/cuckoo/common/integrations/parse_rdp.py @@ -1,12 +1,12 @@ # From https://github.com/wmetcalf/rdp_holiday -import json import argparse import base64 -from struct import unpack - +import json import sys from hashlib import sha1, sha256 +from struct import unpack + from cryptography.hazmat.primitives import hashes from cryptography.hazmat.primitives.serialization import pkcs7 @@ -59,6 +59,7 @@ "signscope": re.compile(r"signscope\s*:\s*s\s*:\s*(.*)", re.I), } + def parse_rdp_file(file_path): rdp_properties = {} @@ -92,7 +93,9 @@ def parse_rdp_file(file_path): print("full_address is a required field... what sort of nonsense are you trying to feed me?") return rdp_properties if "full_address" not in rdp_properties: - print("full_address is a required field but is not in parsed Properties what sort of nonsense are you trying to feed me?") + print( + "full_address is a required field but is not in parsed Properties what sort of nonsense are you trying to feed me?" + ) return rdp_properties if "signature" in rdp_properties: From 8e8d19cf3a139c1c986fd2957c5667324e686ed9 Mon Sep 17 00:00:00 2001 From: doomedraven Date: Tue, 5 Nov 2024 22:31:31 +0100 Subject: [PATCH 049/121] Update report_doc.py --- modules/reporting/report_doc.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/modules/reporting/report_doc.py b/modules/reporting/report_doc.py index 83b8c6019bc..9d790239104 100644 --- a/modules/reporting/report_doc.py +++ b/modules/reporting/report_doc.py @@ -57,7 +57,13 @@ def get_json_document(results, analysis_path): # Create a copy of the dictionary. This is done in order to not modify # the original dictionary and possibly # compromise the following reporting modules. - report = copy.deepcopy(results) + try: + report = copy.deepcopy(results) + except AttributeError: + if "memory" in results: + del results["memory"] + log.error("Deleting Volatility results") + report = copy.deepcopy(results) if "network" not in report: report["network"] = {} From 9f2525cae22e25dec20d3761181acdd74df80e4c Mon Sep 17 00:00:00 2001 From: doomedraven Date: Wed, 6 Nov 2024 15:27:25 +0100 Subject: [PATCH 050/121] parse_rdp --- .../common/integrations/file_extra_info.py | 2 +- modules/processing/network.py | 2 + .../analysis/generic/_file_info.html | 2 + web/templates/analysis/generic/_rdp.html | 70 +++++++++++++++++++ 4 files changed, 75 insertions(+), 1 deletion(-) create mode 100644 web/templates/analysis/generic/_rdp.html diff --git a/lib/cuckoo/common/integrations/file_extra_info.py b/lib/cuckoo/common/integrations/file_extra_info.py index f77541e4bc2..0030df91bca 100644 --- a/lib/cuckoo/common/integrations/file_extra_info.py +++ b/lib/cuckoo/common/integrations/file_extra_info.py @@ -206,7 +206,7 @@ def static_file_info( log.error("procyon_path specified in processing.conf but the file does not exist") else: data_dictionary["java"] = Java(file_path, selfextract_conf.procyon.binary).run() - elif file_path.endswith(".rdp"): + elif file_path.endswith(".rdp") or data_dictionary.get("name", {}).endswith(".rdp"): data_dictionary["rdp"] = parse_rdp_file(file_path) # It's possible to fool libmagic into thinking our 2007+ file is a zip. # So until we have static analysis for zip files, we can use oleid to fail us out silently, diff --git a/modules/processing/network.py b/modules/processing/network.py index f1edfd3edd6..166a4f755d9 100644 --- a/modules/processing/network.py +++ b/modules/processing/network.py @@ -1080,6 +1080,8 @@ def run(self): class NetworkAnalysis(Processing): """Network analysis.""" + key = "network" + # ToDo map this to suricata.tls.ja def _import_ja3_fprints(self): """ diff --git a/web/templates/analysis/generic/_file_info.html b/web/templates/analysis/generic/_file_info.html index 493d8d1c07b..241f95e3a5d 100644 --- a/web/templates/analysis/generic/_file_info.html +++ b/web/templates/analysis/generic/_file_info.html @@ -258,6 +258,7 @@ {% if file.dotnet %}{% endif %} {% if file.pdf %}{% endif %} {% if file.lnk %}{% endif %} + {% if file.rdp %}{% endif %} {% if file.java %}{% endif %} {% if file.office %}{% endif %} {% if file.office.XLMMacroDeobfuscator %}{% endif %} @@ -437,6 +438,7 @@ {% if file.dotnet %}
{% include "analysis/generic/_dotnet.html" %}

{% endif %} {% if file.pdf %}
{% include "analysis/generic/_pdf.html" %}

{% endif %} {% if file.lnk %}
{% include "analysis/generic/_lnk.html" %}

{% endif %} + {% if file.rdp %}
{% include "analysis/generic/_rdp.html" %}

{% endif %} {% if file.java %}
{% include "analysis/generic/_java.html" %}

{% endif %} {% if file.office %}
{% include "analysis/generic/_office.html" %}

{% endif %} {% if file.office.XLMMacroDeobfuscator %}
{% include "analysis/generic/_xlmmacro.html" %}

{% endif %} diff --git a/web/templates/analysis/generic/_rdp.html b/web/templates/analysis/generic/_rdp.html new file mode 100644 index 00000000000..076bb802ebf --- /dev/null +++ b/web/templates/analysis/generic/_rdp.html @@ -0,0 +1,70 @@ +
+{% if file.rdp %} +

RDP file details

+
+ + + + + + {% for key, value in file.rdp.items %} + {% if key != "certificates" %} + + + + + {% else %} +
NameValue
{{key}}{{value}}
+ {% for cert in value %} + + + + + + {% if cert.subject %} + + {% endif %} + {% if cert.issuer %} + + + + + {% endif %} + {% if cert.not_before %} + + + + + {% endif %} + {% if cert.not_after %} + + + + + {% endif %} + {% if cert.serial_number %} + + + + + {% endif %} + {% if cert.fingerprint_sha256 %} + + + + + {% endif %} + {% if cert.fingerprint_sha1 %} + + + + + {% endif %} +
CertificateValue
Subject Organization Name {{cert.subject}}
Issuer{{cert.issuer}}
Not valid before{{cert.not_before}}
Not valid after{{cert.not_after}}
Serial number{{cert.serial_number}}
Cert's sha256 fingerprint{{cert.fingerprint_sha256}}
Cert's sha1 fingerprint{{cert.fingerprint_sha1}}
+ {% endfor %} + {% endif %} + {% endfor %} +{% else %} + Nothing to display. +{% endif %} +
From 81d9555c86d5b7a78f2051ce41d6b8d36d25af2b Mon Sep 17 00:00:00 2001 From: doomedraven Date: Thu, 7 Nov 2024 09:22:18 +0100 Subject: [PATCH 051/121] cape parsers config --- conf/default/processing.conf.default | 4 ++++ lib/cuckoo/common/cape_utils.py | 5 ++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/conf/default/processing.conf.default b/conf/default/processing.conf.default index dbd297d6286..0b400592330 100644 --- a/conf/default/processing.conf.default +++ b/conf/default/processing.conf.default @@ -310,6 +310,10 @@ modules_path = modules/processing/parsers/malduck/ enabled = yes # Must ends with / modules_path = modules/processing/parsers/CAPE/ +# Config parsers all/core/community +parsers = all +# list of comma separated parsers. Ex: stealc,lumma +exclude= # Community [reversinglabs] diff --git a/lib/cuckoo/common/cape_utils.py b/lib/cuckoo/common/cape_utils.py index 75ca6fca0c6..bbcb2fdd862 100644 --- a/lib/cuckoo/common/cape_utils.py +++ b/lib/cuckoo/common/cape_utils.py @@ -94,7 +94,10 @@ cape_malware_parsers = {} if HAVE_CAPE_EXTRACTORS: - cape_malware_parsers = load_cape_parsers() + exclude_parsers = [] + if process_cfg.CAPE_extractors.parsers: + exclude_parsers = [parser_name.strip() for parser_name in process_cfg.CAPE_extractors.parsers.split(",")] + cape_malware_parsers = load_cape_parsers(load=process_cfg.CAPE_extractors.parsers, exclude_parsers=exclude_parsers) # Custom overwrites core cape_malware_parsers.update(cape_load_custom_decoders(CUCKOO_ROOT)) if cape_malware_parsers: From fa1f925e285386ee838852f2cb979018378619f2 Mon Sep 17 00:00:00 2001 From: doomedraven Date: Thu, 7 Nov 2024 10:20:41 +0100 Subject: [PATCH 052/121] disable yara_x due to performance --- lib/cuckoo/common/objects.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/cuckoo/common/objects.py b/lib/cuckoo/common/objects.py index 16c957384b3..ca9693ca452 100644 --- a/lib/cuckoo/common/objects.py +++ b/lib/cuckoo/common/objects.py @@ -74,13 +74,15 @@ print("Missed library. Run: poetry install") HAVE_YARA = False +HAVE_YARA_X = False +""" try: import yara_x HAVE_YARA_X = True except ImportError: # print("Missed library. Run: poetry install pip3 install yara-x") - HAVE_YARA_X = False +""" log = logging.getLogger(__name__) From 8bcdbc581e96d0032d32593e292776bfee3c3c6c Mon Sep 17 00:00:00 2001 From: Kevin O'Reilly Date: Fri, 8 Nov 2024 12:29:42 +0000 Subject: [PATCH 053/121] Update SmokeLoader detection --- data/yara/CAPE/SmokeLoader.yar | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/yara/CAPE/SmokeLoader.yar b/data/yara/CAPE/SmokeLoader.yar index f593544fe5c..46b2a12f721 100644 --- a/data/yara/CAPE/SmokeLoader.yar +++ b/data/yara/CAPE/SmokeLoader.yar @@ -7,7 +7,7 @@ rule SmokeLoader strings: $rc4_decrypt64 = {41 8D 41 01 44 0F B6 C8 42 0F B6 [2] 41 8D 04 12 44 0F B6 D0 42 8A [2] 42 88 [2] 42 88 [2] 42 0F B6 [2] 03 CA 0F B6 C1 8A [2] 30 0F 48 FF C7 49 FF CB 75} $rc4_decrypt32 = {47 B9 FF 00 00 00 23 F9 8A 54 [2] 0F B6 C2 03 F0 23 F1 8A 44 [2] 88 44 [2] 88 54 [2] 0F B6 4C [2] 0F B6 C2 03 C8 81 E1 FF 00 00 00 8A 44 [2] 30 04 2B 43 3B 9C 24 [4] 72 C0} - $fetch_c2_64 = {00 48 8D 05 [3] FF 48 8B CB 48 8B 14 D0 48 8B 5C 24 ?? 48 83 C4 20 5F E9} + $fetch_c2_64 = {84 ?? 74 ?? B? E8 03 00 00 B9 58 02 00 00 FF [5] 48 FF C? 75 F0} $fetch_c2_32 = {8B 96 [2] (00|01) 00 8B CE 5E 8B 14 95 [4] E9} condition: 2 of them From 402531523c4cc48ce3bc2ede2f9077b0658a8472 Mon Sep 17 00:00:00 2001 From: doomedraven Date: Fri, 8 Nov 2024 21:08:08 +0100 Subject: [PATCH 054/121] Update cape_utils.py --- lib/cuckoo/common/cape_utils.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/cuckoo/common/cape_utils.py b/lib/cuckoo/common/cape_utils.py index 75ca6fca0c6..00da1c09d8b 100644 --- a/lib/cuckoo/common/cape_utils.py +++ b/lib/cuckoo/common/cape_utils.py @@ -99,7 +99,9 @@ cape_malware_parsers.update(cape_load_custom_decoders(CUCKOO_ROOT)) if cape_malware_parsers: HAVE_CAPE_EXTRACTORS = True - assert "test cape" in cape_malware_parsers + if "test cape" not in cape_malware_parsers + log.info("Missed cape-parsers! Run: poetry install") + suppress_parsing_list = ["Cerber", "Emotet_Payload", "Ursnif", "QakBot"] From 584c0374695479cd6da4e37e82fb39ebf7956de7 Mon Sep 17 00:00:00 2001 From: doomedraven Date: Sat, 9 Nov 2024 08:04:42 +0100 Subject: [PATCH 055/121] Update cape_utils.py --- lib/cuckoo/common/cape_utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/cuckoo/common/cape_utils.py b/lib/cuckoo/common/cape_utils.py index d0fd1ff6576..f340a84ac2c 100644 --- a/lib/cuckoo/common/cape_utils.py +++ b/lib/cuckoo/common/cape_utils.py @@ -102,7 +102,7 @@ cape_malware_parsers.update(cape_load_custom_decoders(CUCKOO_ROOT)) if cape_malware_parsers: HAVE_CAPE_EXTRACTORS = True - if "test cape" not in cape_malware_parsers + if "test cape" not in cape_malware_parsers: log.info("Missed cape-parsers! Run: poetry install") From 6fbfc155a7e4bdd89805079139e4268bbfc65139 Mon Sep 17 00:00:00 2001 From: GitHub Actions Date: Sat, 9 Nov 2024 07:05:40 +0000 Subject: [PATCH 056/121] style: Automatic code formatting --- lib/cuckoo/common/cape_utils.py | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/cuckoo/common/cape_utils.py b/lib/cuckoo/common/cape_utils.py index f340a84ac2c..38c8ef99400 100644 --- a/lib/cuckoo/common/cape_utils.py +++ b/lib/cuckoo/common/cape_utils.py @@ -106,7 +106,6 @@ log.info("Missed cape-parsers! Run: poetry install") - suppress_parsing_list = ["Cerber", "Emotet_Payload", "Ursnif", "QakBot"] pe_map = { From 217a63524045bc7e75dcce5b7aea3307dbd323cc Mon Sep 17 00:00:00 2001 From: doomedraven Date: Sat, 9 Nov 2024 08:09:07 +0100 Subject: [PATCH 057/121] Update objects.py --- lib/cuckoo/common/objects.py | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/cuckoo/common/objects.py b/lib/cuckoo/common/objects.py index ca9693ca452..338d342f87f 100644 --- a/lib/cuckoo/common/objects.py +++ b/lib/cuckoo/common/objects.py @@ -75,6 +75,7 @@ HAVE_YARA = False HAVE_YARA_X = False +yara_x = False """ try: import yara_x From 9db650124f7a3aa0643928ce4ecd3c200eeb76ea Mon Sep 17 00:00:00 2001 From: doomedraven Date: Tue, 12 Nov 2024 12:29:37 +0100 Subject: [PATCH 058/121] Update file_extra_info.py --- lib/cuckoo/common/integrations/file_extra_info.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/cuckoo/common/integrations/file_extra_info.py b/lib/cuckoo/common/integrations/file_extra_info.py index 0030df91bca..404fa5b844f 100644 --- a/lib/cuckoo/common/integrations/file_extra_info.py +++ b/lib/cuckoo/common/integrations/file_extra_info.py @@ -747,8 +747,9 @@ def kixtart_extract(file: str, **_) -> ExtractorReturnType: @time_tracker def UnAutoIt_extract(file: str, *, data_dictionary: dict, **_) -> ExtractorReturnType: global UN_AUTOIT_NOTIF - if all(block.get("name") not in ("AutoIT_Compiled", "AutoIT_Script") for block in data_dictionary.get("yara", {})): - return + merged_lists = data_dictionary.get("yara", []) + data_dictionary.get("cape_yara", []) + if all(not block.get("name", "").lower().startswith("autoit") for block in merged_lists): + return # this is useless to notify in each iteration if not UN_AUTOIT_NOTIF and not path_exists(unautoit_binary): From 46db06a7b7f6ed6def6bec5a36d9910c6bf00339 Mon Sep 17 00:00:00 2001 From: GitHub Actions Date: Tue, 12 Nov 2024 11:30:28 +0000 Subject: [PATCH 059/121] style: Automatic code formatting --- lib/cuckoo/common/integrations/file_extra_info.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/cuckoo/common/integrations/file_extra_info.py b/lib/cuckoo/common/integrations/file_extra_info.py index 404fa5b844f..c0a4b48219c 100644 --- a/lib/cuckoo/common/integrations/file_extra_info.py +++ b/lib/cuckoo/common/integrations/file_extra_info.py @@ -749,7 +749,7 @@ def UnAutoIt_extract(file: str, *, data_dictionary: dict, **_) -> ExtractorRetur global UN_AUTOIT_NOTIF merged_lists = data_dictionary.get("yara", []) + data_dictionary.get("cape_yara", []) if all(not block.get("name", "").lower().startswith("autoit") for block in merged_lists): - return + return # this is useless to notify in each iteration if not UN_AUTOIT_NOTIF and not path_exists(unautoit_binary): From ec45b2611f46eb834f59338a8dc3c295b05dea7f Mon Sep 17 00:00:00 2001 From: Kevin O'Reilly Date: Tue, 12 Nov 2024 15:03:36 +0000 Subject: [PATCH 060/121] SmokeLoader detection update --- data/yara/CAPE/SmokeLoader.yar | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/data/yara/CAPE/SmokeLoader.yar b/data/yara/CAPE/SmokeLoader.yar index 46b2a12f721..988425e5421 100644 --- a/data/yara/CAPE/SmokeLoader.yar +++ b/data/yara/CAPE/SmokeLoader.yar @@ -7,8 +7,8 @@ rule SmokeLoader strings: $rc4_decrypt64 = {41 8D 41 01 44 0F B6 C8 42 0F B6 [2] 41 8D 04 12 44 0F B6 D0 42 8A [2] 42 88 [2] 42 88 [2] 42 0F B6 [2] 03 CA 0F B6 C1 8A [2] 30 0F 48 FF C7 49 FF CB 75} $rc4_decrypt32 = {47 B9 FF 00 00 00 23 F9 8A 54 [2] 0F B6 C2 03 F0 23 F1 8A 44 [2] 88 44 [2] 88 54 [2] 0F B6 4C [2] 0F B6 C2 03 C8 81 E1 FF 00 00 00 8A 44 [2] 30 04 2B 43 3B 9C 24 [4] 72 C0} - $fetch_c2_64 = {84 ?? 74 ?? B? E8 03 00 00 B9 58 02 00 00 FF [5] 48 FF C? 75 F0} + $fetch_c2_64 = {74 ?? B? E8 03 00 00 B9 58 02 00 00 FF [5] 48 FF C? 75 F0 [6-10] 48 8D 05} $fetch_c2_32 = {8B 96 [2] (00|01) 00 8B CE 5E 8B 14 95 [4] E9} condition: - 2 of them + 2 of them } From 3cd9478f1a3250482fb62b8c56a7c40bc5fd5391 Mon Sep 17 00:00:00 2001 From: doomedraven Date: Tue, 12 Nov 2024 16:39:15 +0100 Subject: [PATCH 061/121] cape-parsers --- poetry.lock | 347 ++++++++++++++++--------------------------------- pyproject.toml | 8 +- 2 files changed, 120 insertions(+), 235 deletions(-) diff --git a/poetry.lock b/poetry.lock index 2c4b225cef7..5d0611caa30 100644 --- a/poetry.lock +++ b/poetry.lock @@ -263,13 +263,13 @@ files = [ [[package]] name = "cape-parsers" -version = "0.1.4" +version = "0.1.8" description = "CAPE: Malware Configuration Extraction" optional = false python-versions = "<4.0,>=3.10" files = [ - {file = "cape_parsers-0.1.4-py3-none-any.whl", hash = "sha256:4957cfd4c4215c550a27ca8d3dd87a60dd834fc6b7785cf0785d35ce04211e72"}, - {file = "cape_parsers-0.1.4.tar.gz", hash = "sha256:00a0541d9947257cacb6485ab513dee46812a90c22883bcc8c5eef592ff8750f"}, + {file = "cape_parsers-0.1.8-py3-none-any.whl", hash = "sha256:9f8957c8f153474c1e8e2688d0638b69da90ac729f67c1ff9ecb38d8214e3d8f"}, + {file = "cape_parsers-0.1.8.tar.gz", hash = "sha256:b86a663d426c9d60cc45c00da06bb374e64ca8fa5741931e34bfe22f77772ea8"}, ] [package.dependencies] @@ -280,7 +280,7 @@ netstruct = "1.1.2" pefile = "*" pycryptodomex = ">=3.20.0" rat-king-parser = ">=3.1.3" -regex = ">=2024.9.11" +ruff = ">=0.7.2" unicorn = "2.1.1" yara-python = "4.5.1" @@ -1398,13 +1398,13 @@ idna = ">=2.5" [[package]] name = "identify" -version = "2.6.1" +version = "2.6.2" description = "File identification library for Python" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "identify-2.6.1-py2.py3-none-any.whl", hash = "sha256:53863bcac7caf8d2ed85bd20312ea5dcfc22226800f6d6881f232d861db5a8f0"}, - {file = "identify-2.6.1.tar.gz", hash = "sha256:91478c5fb7c3aac5ff7bf9b4344f803843dc586832d5f110d672b19aa1984c98"}, + {file = "identify-2.6.2-py2.py3-none-any.whl", hash = "sha256:c097384259f49e372f4ea00a19719d95ae27dd5ff0fd77ad630aa891306b82f3"}, + {file = "identify-2.6.2.tar.gz", hash = "sha256:fab5c716c24d7a789775228823797296a2994b075fb6080ac83a102772a98cbd"}, ] [package.extras] @@ -2997,13 +2997,13 @@ pycryptodomex = "*" [[package]] name = "rat-king-parser" -version = "3.1.3" +version = "3.1.5" description = "A robust, multiprocessing-capable, multi-family RAT config parser/config extractor for AsyncRAT, DcRAT, VenomRAT, QuasarRAT, XWorm, Xeno RAT, and cloned/derivative RAT families." optional = false python-versions = ">=3.10" files = [ - {file = "rat_king_parser-3.1.3-py3-none-any.whl", hash = "sha256:229c7d4565e7c0ea3e6a75a8252df9223286a26b77b2d449c2612b95c8406605"}, - {file = "rat_king_parser-3.1.3.tar.gz", hash = "sha256:cd662eb127c1bb85345a4460439608cfc87b82e833503b632d5ccc713eb49123"}, + {file = "rat_king_parser-3.1.5-py3-none-any.whl", hash = "sha256:8bfccf381ce8647d66f54a46bbaca4d74765af206a37615c430ca5ac7526b213"}, + {file = "rat_king_parser-3.1.5.tar.gz", hash = "sha256:0a2a97160cbad468df5149a28f1ee8aae6099206ffcd894dfadb43920c80bb11"}, ] [package.dependencies] @@ -3014,109 +3014,6 @@ yara-python = "*" [package.extras] maco = ["maco", "validators"] -[[package]] -name = "regex" -version = "2024.9.11" -description = "Alternative regular expression module, to replace re." -optional = false -python-versions = ">=3.8" -files = [ - {file = "regex-2024.9.11-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:1494fa8725c285a81d01dc8c06b55287a1ee5e0e382d8413adc0a9197aac6408"}, - {file = "regex-2024.9.11-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0e12c481ad92d129c78f13a2a3662317e46ee7ef96c94fd332e1c29131875b7d"}, - {file = "regex-2024.9.11-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:16e13a7929791ac1216afde26f712802e3df7bf0360b32e4914dca3ab8baeea5"}, - {file = "regex-2024.9.11-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:46989629904bad940bbec2106528140a218b4a36bb3042d8406980be1941429c"}, - {file = "regex-2024.9.11-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a906ed5e47a0ce5f04b2c981af1c9acf9e8696066900bf03b9d7879a6f679fc8"}, - {file = "regex-2024.9.11-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e9a091b0550b3b0207784a7d6d0f1a00d1d1c8a11699c1a4d93db3fbefc3ad35"}, - {file = "regex-2024.9.11-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5ddcd9a179c0a6fa8add279a4444015acddcd7f232a49071ae57fa6e278f1f71"}, - {file = "regex-2024.9.11-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6b41e1adc61fa347662b09398e31ad446afadff932a24807d3ceb955ed865cc8"}, - {file = "regex-2024.9.11-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:ced479f601cd2f8ca1fd7b23925a7e0ad512a56d6e9476f79b8f381d9d37090a"}, - {file = "regex-2024.9.11-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:635a1d96665f84b292e401c3d62775851aedc31d4f8784117b3c68c4fcd4118d"}, - {file = "regex-2024.9.11-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:c0256beda696edcf7d97ef16b2a33a8e5a875affd6fa6567b54f7c577b30a137"}, - {file = "regex-2024.9.11-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:3ce4f1185db3fbde8ed8aa223fc9620f276c58de8b0d4f8cc86fd1360829edb6"}, - {file = "regex-2024.9.11-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:09d77559e80dcc9d24570da3745ab859a9cf91953062e4ab126ba9d5993688ca"}, - {file = "regex-2024.9.11-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:7a22ccefd4db3f12b526eccb129390942fe874a3a9fdbdd24cf55773a1faab1a"}, - {file = "regex-2024.9.11-cp310-cp310-win32.whl", hash = "sha256:f745ec09bc1b0bd15cfc73df6fa4f726dcc26bb16c23a03f9e3367d357eeedd0"}, - {file = "regex-2024.9.11-cp310-cp310-win_amd64.whl", hash = "sha256:01c2acb51f8a7d6494c8c5eafe3d8e06d76563d8a8a4643b37e9b2dd8a2ff623"}, - {file = "regex-2024.9.11-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:2cce2449e5927a0bf084d346da6cd5eb016b2beca10d0013ab50e3c226ffc0df"}, - {file = "regex-2024.9.11-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3b37fa423beefa44919e009745ccbf353d8c981516e807995b2bd11c2c77d268"}, - {file = "regex-2024.9.11-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:64ce2799bd75039b480cc0360907c4fb2f50022f030bf9e7a8705b636e408fad"}, - {file = "regex-2024.9.11-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a4cc92bb6db56ab0c1cbd17294e14f5e9224f0cc6521167ef388332604e92679"}, - {file = "regex-2024.9.11-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d05ac6fa06959c4172eccd99a222e1fbf17b5670c4d596cb1e5cde99600674c4"}, - {file = "regex-2024.9.11-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:040562757795eeea356394a7fb13076ad4f99d3c62ab0f8bdfb21f99a1f85664"}, - {file = "regex-2024.9.11-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6113c008a7780792efc80f9dfe10ba0cd043cbf8dc9a76ef757850f51b4edc50"}, - {file = "regex-2024.9.11-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8e5fb5f77c8745a60105403a774fe2c1759b71d3e7b4ca237a5e67ad066c7199"}, - {file = "regex-2024.9.11-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:54d9ff35d4515debf14bc27f1e3b38bfc453eff3220f5bce159642fa762fe5d4"}, - {file = "regex-2024.9.11-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:df5cbb1fbc74a8305b6065d4ade43b993be03dbe0f8b30032cced0d7740994bd"}, - {file = "regex-2024.9.11-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:7fb89ee5d106e4a7a51bce305ac4efb981536301895f7bdcf93ec92ae0d91c7f"}, - {file = "regex-2024.9.11-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:a738b937d512b30bf75995c0159c0ddf9eec0775c9d72ac0202076c72f24aa96"}, - {file = "regex-2024.9.11-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:e28f9faeb14b6f23ac55bfbbfd3643f5c7c18ede093977f1df249f73fd22c7b1"}, - {file = "regex-2024.9.11-cp311-cp311-win32.whl", hash = "sha256:18e707ce6c92d7282dfce370cd205098384b8ee21544e7cb29b8aab955b66fa9"}, - {file = "regex-2024.9.11-cp311-cp311-win_amd64.whl", hash = "sha256:313ea15e5ff2a8cbbad96ccef6be638393041b0a7863183c2d31e0c6116688cf"}, - {file = "regex-2024.9.11-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:b0d0a6c64fcc4ef9c69bd5b3b3626cc3776520a1637d8abaa62b9edc147a58f7"}, - {file = "regex-2024.9.11-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:49b0e06786ea663f933f3710a51e9385ce0cba0ea56b67107fd841a55d56a231"}, - {file = "regex-2024.9.11-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5b513b6997a0b2f10e4fd3a1313568e373926e8c252bd76c960f96fd039cd28d"}, - {file = "regex-2024.9.11-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ee439691d8c23e76f9802c42a95cfeebf9d47cf4ffd06f18489122dbb0a7ad64"}, - {file = "regex-2024.9.11-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a8f877c89719d759e52783f7fe6e1c67121076b87b40542966c02de5503ace42"}, - {file = "regex-2024.9.11-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:23b30c62d0f16827f2ae9f2bb87619bc4fba2044911e2e6c2eb1af0161cdb766"}, - {file = "regex-2024.9.11-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:85ab7824093d8f10d44330fe1e6493f756f252d145323dd17ab6b48733ff6c0a"}, - {file = "regex-2024.9.11-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8dee5b4810a89447151999428fe096977346cf2f29f4d5e29609d2e19e0199c9"}, - {file = "regex-2024.9.11-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:98eeee2f2e63edae2181c886d7911ce502e1292794f4c5ee71e60e23e8d26b5d"}, - {file = "regex-2024.9.11-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:57fdd2e0b2694ce6fc2e5ccf189789c3e2962916fb38779d3e3521ff8fe7a822"}, - {file = "regex-2024.9.11-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:d552c78411f60b1fdaafd117a1fca2f02e562e309223b9d44b7de8be451ec5e0"}, - {file = "regex-2024.9.11-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:a0b2b80321c2ed3fcf0385ec9e51a12253c50f146fddb2abbb10f033fe3d049a"}, - {file = "regex-2024.9.11-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:18406efb2f5a0e57e3a5881cd9354c1512d3bb4f5c45d96d110a66114d84d23a"}, - {file = "regex-2024.9.11-cp312-cp312-win32.whl", hash = "sha256:e464b467f1588e2c42d26814231edecbcfe77f5ac414d92cbf4e7b55b2c2a776"}, - {file = "regex-2024.9.11-cp312-cp312-win_amd64.whl", hash = "sha256:9e8719792ca63c6b8340380352c24dcb8cd7ec49dae36e963742a275dfae6009"}, - {file = "regex-2024.9.11-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:c157bb447303070f256e084668b702073db99bbb61d44f85d811025fcf38f784"}, - {file = "regex-2024.9.11-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:4db21ece84dfeefc5d8a3863f101995de646c6cb0536952c321a2650aa202c36"}, - {file = "regex-2024.9.11-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:220e92a30b426daf23bb67a7962900ed4613589bab80382be09b48896d211e92"}, - {file = "regex-2024.9.11-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eb1ae19e64c14c7ec1995f40bd932448713d3c73509e82d8cd7744dc00e29e86"}, - {file = "regex-2024.9.11-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f47cd43a5bfa48f86925fe26fbdd0a488ff15b62468abb5d2a1e092a4fb10e85"}, - {file = "regex-2024.9.11-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9d4a76b96f398697fe01117093613166e6aa8195d63f1b4ec3f21ab637632963"}, - {file = "regex-2024.9.11-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0ea51dcc0835eea2ea31d66456210a4e01a076d820e9039b04ae8d17ac11dee6"}, - {file = "regex-2024.9.11-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b7aaa315101c6567a9a45d2839322c51c8d6e81f67683d529512f5bcfb99c802"}, - {file = "regex-2024.9.11-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:c57d08ad67aba97af57a7263c2d9006d5c404d721c5f7542f077f109ec2a4a29"}, - {file = "regex-2024.9.11-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:f8404bf61298bb6f8224bb9176c1424548ee1181130818fcd2cbffddc768bed8"}, - {file = "regex-2024.9.11-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:dd4490a33eb909ef5078ab20f5f000087afa2a4daa27b4c072ccb3cb3050ad84"}, - {file = "regex-2024.9.11-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:eee9130eaad130649fd73e5cd92f60e55708952260ede70da64de420cdcad554"}, - {file = "regex-2024.9.11-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6a2644a93da36c784e546de579ec1806bfd2763ef47babc1b03d765fe560c9f8"}, - {file = "regex-2024.9.11-cp313-cp313-win32.whl", hash = "sha256:e997fd30430c57138adc06bba4c7c2968fb13d101e57dd5bb9355bf8ce3fa7e8"}, - {file = "regex-2024.9.11-cp313-cp313-win_amd64.whl", hash = "sha256:042c55879cfeb21a8adacc84ea347721d3d83a159da6acdf1116859e2427c43f"}, - {file = "regex-2024.9.11-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:35f4a6f96aa6cb3f2f7247027b07b15a374f0d5b912c0001418d1d55024d5cb4"}, - {file = "regex-2024.9.11-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:55b96e7ce3a69a8449a66984c268062fbaa0d8ae437b285428e12797baefce7e"}, - {file = "regex-2024.9.11-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:cb130fccd1a37ed894824b8c046321540263013da72745d755f2d35114b81a60"}, - {file = "regex-2024.9.11-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:323c1f04be6b2968944d730e5c2091c8c89767903ecaa135203eec4565ed2b2b"}, - {file = "regex-2024.9.11-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:be1c8ed48c4c4065ecb19d882a0ce1afe0745dfad8ce48c49586b90a55f02366"}, - {file = "regex-2024.9.11-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b5b029322e6e7b94fff16cd120ab35a253236a5f99a79fb04fda7ae71ca20ae8"}, - {file = "regex-2024.9.11-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f6fff13ef6b5f29221d6904aa816c34701462956aa72a77f1f151a8ec4f56aeb"}, - {file = "regex-2024.9.11-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:587d4af3979376652010e400accc30404e6c16b7df574048ab1f581af82065e4"}, - {file = "regex-2024.9.11-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:079400a8269544b955ffa9e31f186f01d96829110a3bf79dc338e9910f794fca"}, - {file = "regex-2024.9.11-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:f9268774428ec173654985ce55fc6caf4c6d11ade0f6f914d48ef4719eb05ebb"}, - {file = "regex-2024.9.11-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:23f9985c8784e544d53fc2930fc1ac1a7319f5d5332d228437acc9f418f2f168"}, - {file = "regex-2024.9.11-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:ae2941333154baff9838e88aa71c1d84f4438189ecc6021a12c7573728b5838e"}, - {file = "regex-2024.9.11-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:e93f1c331ca8e86fe877a48ad64e77882c0c4da0097f2212873a69bbfea95d0c"}, - {file = "regex-2024.9.11-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:846bc79ee753acf93aef4184c040d709940c9d001029ceb7b7a52747b80ed2dd"}, - {file = "regex-2024.9.11-cp38-cp38-win32.whl", hash = "sha256:c94bb0a9f1db10a1d16c00880bdebd5f9faf267273b8f5bd1878126e0fbde771"}, - {file = "regex-2024.9.11-cp38-cp38-win_amd64.whl", hash = "sha256:2b08fce89fbd45664d3df6ad93e554b6c16933ffa9d55cb7e01182baaf971508"}, - {file = "regex-2024.9.11-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:07f45f287469039ffc2c53caf6803cd506eb5f5f637f1d4acb37a738f71dd066"}, - {file = "regex-2024.9.11-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:4838e24ee015101d9f901988001038f7f0d90dc0c3b115541a1365fb439add62"}, - {file = "regex-2024.9.11-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:6edd623bae6a737f10ce853ea076f56f507fd7726bee96a41ee3d68d347e4d16"}, - {file = "regex-2024.9.11-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c69ada171c2d0e97a4b5aa78fbb835e0ffbb6b13fc5da968c09811346564f0d3"}, - {file = "regex-2024.9.11-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:02087ea0a03b4af1ed6ebab2c54d7118127fee8d71b26398e8e4b05b78963199"}, - {file = "regex-2024.9.11-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:69dee6a020693d12a3cf892aba4808fe168d2a4cef368eb9bf74f5398bfd4ee8"}, - {file = "regex-2024.9.11-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:297f54910247508e6e5cae669f2bc308985c60540a4edd1c77203ef19bfa63ca"}, - {file = "regex-2024.9.11-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ecea58b43a67b1b79805f1a0255730edaf5191ecef84dbc4cc85eb30bc8b63b9"}, - {file = "regex-2024.9.11-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:eab4bb380f15e189d1313195b062a6aa908f5bd687a0ceccd47c8211e9cf0d4a"}, - {file = "regex-2024.9.11-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:0cbff728659ce4bbf4c30b2a1be040faafaa9eca6ecde40aaff86f7889f4ab39"}, - {file = "regex-2024.9.11-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:54c4a097b8bc5bb0dfc83ae498061d53ad7b5762e00f4adaa23bee22b012e6ba"}, - {file = "regex-2024.9.11-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:73d6d2f64f4d894c96626a75578b0bf7d9e56dcda8c3d037a2118fdfe9b1c664"}, - {file = "regex-2024.9.11-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:e53b5fbab5d675aec9f0c501274c467c0f9a5d23696cfc94247e1fb56501ed89"}, - {file = "regex-2024.9.11-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:0ffbcf9221e04502fc35e54d1ce9567541979c3fdfb93d2c554f0ca583a19b35"}, - {file = "regex-2024.9.11-cp39-cp39-win32.whl", hash = "sha256:e4c22e1ac1f1ec1e09f72e6c44d8f2244173db7eb9629cc3a346a8d7ccc31142"}, - {file = "regex-2024.9.11-cp39-cp39-win_amd64.whl", hash = "sha256:faa3c142464efec496967359ca99696c896c591c56c53506bac1ad465f66e919"}, - {file = "regex-2024.9.11.tar.gz", hash = "sha256:6c188c307e8433bcb63dc1915022deb553b4203a70722fc542c363bf120a01fd"}, -] - [[package]] name = "requests" version = "2.32.2" @@ -3193,28 +3090,29 @@ jupyter = ["ipywidgets (>=7.5.1,<9)"] [[package]] name = "ruff" -version = "0.0.290" -description = "An extremely fast Python linter, written in Rust." +version = "0.7.3" +description = "An extremely fast Python linter and code formatter, written in Rust." optional = false python-versions = ">=3.7" files = [ - {file = "ruff-0.0.290-py3-none-macosx_10_7_x86_64.whl", hash = "sha256:0e2b09ac4213b11a3520221083866a5816616f3ae9da123037b8ab275066fbac"}, - {file = "ruff-0.0.290-py3-none-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:4ca6285aa77b3d966be32c9a3cd531655b3d4a0171e1f9bf26d66d0372186767"}, - {file = "ruff-0.0.290-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:35e3550d1d9f2157b0fcc77670f7bb59154f223bff281766e61bdd1dd854e0c5"}, - {file = "ruff-0.0.290-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d748c8bd97874f5751aed73e8dde379ce32d16338123d07c18b25c9a2796574a"}, - {file = "ruff-0.0.290-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:982af5ec67cecd099e2ef5e238650407fb40d56304910102d054c109f390bf3c"}, - {file = "ruff-0.0.290-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:bbd37352cea4ee007c48a44c9bc45a21f7ba70a57edfe46842e346651e2b995a"}, - {file = "ruff-0.0.290-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1d9be6351b7889462912e0b8185a260c0219c35dfd920fb490c7f256f1d8313e"}, - {file = "ruff-0.0.290-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:75cdc7fe32dcf33b7cec306707552dda54632ac29402775b9e212a3c16aad5e6"}, - {file = "ruff-0.0.290-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eb07f37f7aecdbbc91d759c0c09870ce0fb3eed4025eebedf9c4b98c69abd527"}, - {file = "ruff-0.0.290-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:2ab41bc0ba359d3f715fc7b705bdeef19c0461351306b70a4e247f836b9350ed"}, - {file = "ruff-0.0.290-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:150bf8050214cea5b990945b66433bf9a5e0cef395c9bc0f50569e7de7540c86"}, - {file = "ruff-0.0.290-py3-none-musllinux_1_2_i686.whl", hash = "sha256:75386ebc15fe5467248c039f5bf6a0cfe7bfc619ffbb8cd62406cd8811815fca"}, - {file = "ruff-0.0.290-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:ac93eadf07bc4ab4c48d8bb4e427bf0f58f3a9c578862eb85d99d704669f5da0"}, - {file = "ruff-0.0.290-py3-none-win32.whl", hash = "sha256:461fbd1fb9ca806d4e3d5c745a30e185f7cf3ca77293cdc17abb2f2a990ad3f7"}, - {file = "ruff-0.0.290-py3-none-win_amd64.whl", hash = "sha256:f1f49f5ec967fd5778813780b12a5650ab0ebcb9ddcca28d642c689b36920796"}, - {file = "ruff-0.0.290-py3-none-win_arm64.whl", hash = "sha256:ae5a92dfbdf1f0c689433c223f8dac0782c2b2584bd502dfdbc76475669f1ba1"}, - {file = "ruff-0.0.290.tar.gz", hash = "sha256:949fecbc5467bb11b8db810a7fa53c7e02633856ee6bd1302b2f43adcd71b88d"}, + {file = "ruff-0.7.3-py3-none-linux_armv6l.whl", hash = "sha256:34f2339dc22687ec7e7002792d1f50712bf84a13d5152e75712ac08be565d344"}, + {file = "ruff-0.7.3-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:fb397332a1879b9764a3455a0bb1087bda876c2db8aca3a3cbb67b3dbce8cda0"}, + {file = "ruff-0.7.3-py3-none-macosx_11_0_arm64.whl", hash = "sha256:37d0b619546103274e7f62643d14e1adcbccb242efda4e4bdb9544d7764782e9"}, + {file = "ruff-0.7.3-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5d59f0c3ee4d1a6787614e7135b72e21024875266101142a09a61439cb6e38a5"}, + {file = "ruff-0.7.3-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:44eb93c2499a169d49fafd07bc62ac89b1bc800b197e50ff4633aed212569299"}, + {file = "ruff-0.7.3-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6d0242ce53f3a576c35ee32d907475a8d569944c0407f91d207c8af5be5dae4e"}, + {file = "ruff-0.7.3-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:6b6224af8b5e09772c2ecb8dc9f3f344c1aa48201c7f07e7315367f6dd90ac29"}, + {file = "ruff-0.7.3-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c50f95a82b94421c964fae4c27c0242890a20fe67d203d127e84fbb8013855f5"}, + {file = "ruff-0.7.3-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7f3eff9961b5d2644bcf1616c606e93baa2d6b349e8aa8b035f654df252c8c67"}, + {file = "ruff-0.7.3-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b8963cab06d130c4df2fd52c84e9f10d297826d2e8169ae0c798b6221be1d1d2"}, + {file = "ruff-0.7.3-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:61b46049d6edc0e4317fb14b33bd693245281a3007288b68a3f5b74a22a0746d"}, + {file = "ruff-0.7.3-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:10ebce7696afe4644e8c1a23b3cf8c0f2193a310c18387c06e583ae9ef284de2"}, + {file = "ruff-0.7.3-py3-none-musllinux_1_2_i686.whl", hash = "sha256:3f36d56326b3aef8eeee150b700e519880d1aab92f471eefdef656fd57492aa2"}, + {file = "ruff-0.7.3-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:5d024301109a0007b78d57ab0ba190087b43dce852e552734ebf0b0b85e4fb16"}, + {file = "ruff-0.7.3-py3-none-win32.whl", hash = "sha256:4ba81a5f0c5478aa61674c5a2194de8b02652f17addf8dfc40c8937e6e7d79fc"}, + {file = "ruff-0.7.3-py3-none-win_amd64.whl", hash = "sha256:588a9ff2fecf01025ed065fe28809cd5a53b43505f48b69a1ac7707b1b7e4088"}, + {file = "ruff-0.7.3-py3-none-win_arm64.whl", hash = "sha256:1713e2c5545863cdbfe2cbce21f69ffaf37b813bfd1fb3b90dc9a6f1963f5a8c"}, + {file = "ruff-0.7.3.tar.gz", hash = "sha256:e1d1ba2e40b6e71a61b063354d04be669ab0d39c352461f3d789cac68b54a313"}, ] [[package]] @@ -3537,13 +3435,13 @@ doc = ["reno", "sphinx", "tornado (>=4.5)"] [[package]] name = "tldextract" -version = "5.1.2" +version = "5.1.3" description = "Accurately separates a URL's subdomain, domain, and public suffix, using the Public Suffix List (PSL). By default, this includes the public ICANN TLDs and their exceptions. You can optionally support the Public Suffix List's private domains as well." optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "tldextract-5.1.2-py3-none-any.whl", hash = "sha256:4dfc4c277b6b97fa053899fcdb892d2dc27295851ab5fac4e07797b6a21b2e46"}, - {file = "tldextract-5.1.2.tar.gz", hash = "sha256:c9e17f756f05afb5abac04fe8f766e7e70f9fe387adb1859f0f52408ee060200"}, + {file = "tldextract-5.1.3-py3-none-any.whl", hash = "sha256:78de310cc2ca018692de5ddf320f9d6bd7c5cf857d0fd4f2175f0cdf4440ea75"}, + {file = "tldextract-5.1.3.tar.gz", hash = "sha256:d43c7284c23f5dc8a42fd0fee2abede2ff74cc622674e4cb07f514ab3330c338"}, ] [package.dependencies] @@ -3554,17 +3452,17 @@ requests-file = ">=1.4" [package.extras] release = ["build", "twine"] -testing = ["black", "mypy", "pytest", "pytest-gitignore", "pytest-mock", "responses", "ruff", "syrupy", "tox", "types-filelock", "types-requests"] +testing = ["mypy", "pytest", "pytest-gitignore", "pytest-mock", "responses", "ruff", "syrupy", "tox", "tox-uv", "types-filelock", "types-requests"] [[package]] name = "tomli" -version = "2.0.2" +version = "2.1.0" description = "A lil' TOML parser" optional = false python-versions = ">=3.8" files = [ - {file = "tomli-2.0.2-py3-none-any.whl", hash = "sha256:2ebe24485c53d303f690b0ec092806a085f07af5a5aa1464f3931eec36caaa38"}, - {file = "tomli-2.0.2.tar.gz", hash = "sha256:d46d457a85337051c36524bc5349dd91b1877838e2979ac5ced3e710ed8a60ed"}, + {file = "tomli-2.1.0-py3-none-any.whl", hash = "sha256:a5c57c3d1c56f5ccdf89f6523458f60ef716e210fc47c4cfb188c5ba473e0391"}, + {file = "tomli-2.1.0.tar.gz", hash = "sha256:3f646cae2aec94e17d04973e4249548320197cfabdf130015d023de4b74d8ab8"}, ] [[package]] @@ -3873,97 +3771,80 @@ anyio = ">=3.0.0" [[package]] name = "websockets" -version = "13.1" +version = "14.0" description = "An implementation of the WebSocket Protocol (RFC 6455 & 7692)" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "websockets-13.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:f48c749857f8fb598fb890a75f540e3221d0976ed0bf879cf3c7eef34151acee"}, - {file = "websockets-13.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c7e72ce6bda6fb9409cc1e8164dd41d7c91466fb599eb047cfda72fe758a34a7"}, - {file = "websockets-13.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f779498eeec470295a2b1a5d97aa1bc9814ecd25e1eb637bd9d1c73a327387f6"}, - {file = "websockets-13.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4676df3fe46956fbb0437d8800cd5f2b6d41143b6e7e842e60554398432cf29b"}, - {file = "websockets-13.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a7affedeb43a70351bb811dadf49493c9cfd1ed94c9c70095fd177e9cc1541fa"}, - {file = "websockets-13.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1971e62d2caa443e57588e1d82d15f663b29ff9dfe7446d9964a4b6f12c1e700"}, - {file = "websockets-13.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:5f2e75431f8dc4a47f31565a6e1355fb4f2ecaa99d6b89737527ea917066e26c"}, - {file = "websockets-13.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:58cf7e75dbf7e566088b07e36ea2e3e2bd5676e22216e4cad108d4df4a7402a0"}, - {file = "websockets-13.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:c90d6dec6be2c7d03378a574de87af9b1efea77d0c52a8301dd831ece938452f"}, - {file = "websockets-13.1-cp310-cp310-win32.whl", hash = "sha256:730f42125ccb14602f455155084f978bd9e8e57e89b569b4d7f0f0c17a448ffe"}, - {file = "websockets-13.1-cp310-cp310-win_amd64.whl", hash = "sha256:5993260f483d05a9737073be197371940c01b257cc45ae3f1d5d7adb371b266a"}, - {file = "websockets-13.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:61fc0dfcda609cda0fc9fe7977694c0c59cf9d749fbb17f4e9483929e3c48a19"}, - {file = "websockets-13.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ceec59f59d092c5007e815def4ebb80c2de330e9588e101cf8bd94c143ec78a5"}, - {file = "websockets-13.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c1dca61c6db1166c48b95198c0b7d9c990b30c756fc2923cc66f68d17dc558fd"}, - {file = "websockets-13.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:308e20f22c2c77f3f39caca508e765f8725020b84aa963474e18c59accbf4c02"}, - {file = "websockets-13.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:62d516c325e6540e8a57b94abefc3459d7dab8ce52ac75c96cad5549e187e3a7"}, - {file = "websockets-13.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:87c6e35319b46b99e168eb98472d6c7d8634ee37750d7693656dc766395df096"}, - {file = "websockets-13.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:5f9fee94ebafbc3117c30be1844ed01a3b177bb6e39088bc6b2fa1dc15572084"}, - {file = "websockets-13.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:7c1e90228c2f5cdde263253fa5db63e6653f1c00e7ec64108065a0b9713fa1b3"}, - {file = "websockets-13.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:6548f29b0e401eea2b967b2fdc1c7c7b5ebb3eeb470ed23a54cd45ef078a0db9"}, - {file = "websockets-13.1-cp311-cp311-win32.whl", hash = "sha256:c11d4d16e133f6df8916cc5b7e3e96ee4c44c936717d684a94f48f82edb7c92f"}, - {file = "websockets-13.1-cp311-cp311-win_amd64.whl", hash = "sha256:d04f13a1d75cb2b8382bdc16ae6fa58c97337253826dfe136195b7f89f661557"}, - {file = "websockets-13.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:9d75baf00138f80b48f1eac72ad1535aac0b6461265a0bcad391fc5aba875cfc"}, - {file = "websockets-13.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:9b6f347deb3dcfbfde1c20baa21c2ac0751afaa73e64e5b693bb2b848efeaa49"}, - {file = "websockets-13.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:de58647e3f9c42f13f90ac7e5f58900c80a39019848c5547bc691693098ae1bd"}, - {file = "websockets-13.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a1b54689e38d1279a51d11e3467dd2f3a50f5f2e879012ce8f2d6943f00e83f0"}, - {file = "websockets-13.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cf1781ef73c073e6b0f90af841aaf98501f975d306bbf6221683dd594ccc52b6"}, - {file = "websockets-13.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8d23b88b9388ed85c6faf0e74d8dec4f4d3baf3ecf20a65a47b836d56260d4b9"}, - {file = "websockets-13.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3c78383585f47ccb0fcf186dcb8a43f5438bd7d8f47d69e0b56f71bf431a0a68"}, - {file = "websockets-13.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:d6d300f8ec35c24025ceb9b9019ae9040c1ab2f01cddc2bcc0b518af31c75c14"}, - {file = "websockets-13.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:a9dcaf8b0cc72a392760bb8755922c03e17a5a54e08cca58e8b74f6902b433cf"}, - {file = "websockets-13.1-cp312-cp312-win32.whl", hash = "sha256:2f85cf4f2a1ba8f602298a853cec8526c2ca42a9a4b947ec236eaedb8f2dc80c"}, - {file = "websockets-13.1-cp312-cp312-win_amd64.whl", hash = "sha256:38377f8b0cdeee97c552d20cf1865695fcd56aba155ad1b4ca8779a5b6ef4ac3"}, - {file = "websockets-13.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:a9ab1e71d3d2e54a0aa646ab6d4eebfaa5f416fe78dfe4da2839525dc5d765c6"}, - {file = "websockets-13.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:b9d7439d7fab4dce00570bb906875734df13d9faa4b48e261c440a5fec6d9708"}, - {file = "websockets-13.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:327b74e915cf13c5931334c61e1a41040e365d380f812513a255aa804b183418"}, - {file = "websockets-13.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:325b1ccdbf5e5725fdcb1b0e9ad4d2545056479d0eee392c291c1bf76206435a"}, - {file = "websockets-13.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:346bee67a65f189e0e33f520f253d5147ab76ae42493804319b5716e46dddf0f"}, - {file = "websockets-13.1-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:91a0fa841646320ec0d3accdff5b757b06e2e5c86ba32af2e0815c96c7a603c5"}, - {file = "websockets-13.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:18503d2c5f3943e93819238bf20df71982d193f73dcecd26c94514f417f6b135"}, - {file = "websockets-13.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:a9cd1af7e18e5221d2878378fbc287a14cd527fdd5939ed56a18df8a31136bb2"}, - {file = "websockets-13.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:70c5be9f416aa72aab7a2a76c90ae0a4fe2755c1816c153c1a2bcc3333ce4ce6"}, - {file = "websockets-13.1-cp313-cp313-win32.whl", hash = "sha256:624459daabeb310d3815b276c1adef475b3e6804abaf2d9d2c061c319f7f187d"}, - {file = "websockets-13.1-cp313-cp313-win_amd64.whl", hash = "sha256:c518e84bb59c2baae725accd355c8dc517b4a3ed8db88b4bc93c78dae2974bf2"}, - {file = "websockets-13.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:c7934fd0e920e70468e676fe7f1b7261c1efa0d6c037c6722278ca0228ad9d0d"}, - {file = "websockets-13.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:149e622dc48c10ccc3d2760e5f36753db9cacf3ad7bc7bbbfd7d9c819e286f23"}, - {file = "websockets-13.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:a569eb1b05d72f9bce2ebd28a1ce2054311b66677fcd46cf36204ad23acead8c"}, - {file = "websockets-13.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:95df24ca1e1bd93bbca51d94dd049a984609687cb2fb08a7f2c56ac84e9816ea"}, - {file = "websockets-13.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d8dbb1bf0c0a4ae8b40bdc9be7f644e2f3fb4e8a9aca7145bfa510d4a374eeb7"}, - {file = "websockets-13.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:035233b7531fb92a76beefcbf479504db8c72eb3bff41da55aecce3a0f729e54"}, - {file = "websockets-13.1-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:e4450fc83a3df53dec45922b576e91e94f5578d06436871dce3a6be38e40f5db"}, - {file = "websockets-13.1-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:463e1c6ec853202dd3657f156123d6b4dad0c546ea2e2e38be2b3f7c5b8e7295"}, - {file = "websockets-13.1-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:6d6855bbe70119872c05107e38fbc7f96b1d8cb047d95c2c50869a46c65a8e96"}, - {file = "websockets-13.1-cp38-cp38-win32.whl", hash = "sha256:204e5107f43095012b00f1451374693267adbb832d29966a01ecc4ce1db26faf"}, - {file = "websockets-13.1-cp38-cp38-win_amd64.whl", hash = "sha256:485307243237328c022bc908b90e4457d0daa8b5cf4b3723fd3c4a8012fce4c6"}, - {file = "websockets-13.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:9b37c184f8b976f0c0a231a5f3d6efe10807d41ccbe4488df8c74174805eea7d"}, - {file = "websockets-13.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:163e7277e1a0bd9fb3c8842a71661ad19c6aa7bb3d6678dc7f89b17fbcc4aeb7"}, - {file = "websockets-13.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4b889dbd1342820cc210ba44307cf75ae5f2f96226c0038094455a96e64fb07a"}, - {file = "websockets-13.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:586a356928692c1fed0eca68b4d1c2cbbd1ca2acf2ac7e7ebd3b9052582deefa"}, - {file = "websockets-13.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7bd6abf1e070a6b72bfeb71049d6ad286852e285f146682bf30d0296f5fbadfa"}, - {file = "websockets-13.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6d2aad13a200e5934f5a6767492fb07151e1de1d6079c003ab31e1823733ae79"}, - {file = "websockets-13.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:df01aea34b6e9e33572c35cd16bae5a47785e7d5c8cb2b54b2acdb9678315a17"}, - {file = "websockets-13.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:e54affdeb21026329fb0744ad187cf812f7d3c2aa702a5edb562b325191fcab6"}, - {file = "websockets-13.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:9ef8aa8bdbac47f4968a5d66462a2a0935d044bf35c0e5a8af152d58516dbeb5"}, - {file = "websockets-13.1-cp39-cp39-win32.whl", hash = "sha256:deeb929efe52bed518f6eb2ddc00cc496366a14c726005726ad62c2dd9017a3c"}, - {file = "websockets-13.1-cp39-cp39-win_amd64.whl", hash = "sha256:7c65ffa900e7cc958cd088b9a9157a8141c991f8c53d11087e6fb7277a03f81d"}, - {file = "websockets-13.1-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:5dd6da9bec02735931fccec99d97c29f47cc61f644264eb995ad6c0c27667238"}, - {file = "websockets-13.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:2510c09d8e8df777177ee3d40cd35450dc169a81e747455cc4197e63f7e7bfe5"}, - {file = "websockets-13.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f1c3cf67185543730888b20682fb186fc8d0fa6f07ccc3ef4390831ab4b388d9"}, - {file = "websockets-13.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bcc03c8b72267e97b49149e4863d57c2d77f13fae12066622dc78fe322490fe6"}, - {file = "websockets-13.1-pp310-pypy310_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:004280a140f220c812e65f36944a9ca92d766b6cc4560be652a0a3883a79ed8a"}, - {file = "websockets-13.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:e2620453c075abeb0daa949a292e19f56de518988e079c36478bacf9546ced23"}, - {file = "websockets-13.1-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:9156c45750b37337f7b0b00e6248991a047be4aa44554c9886fe6bdd605aab3b"}, - {file = "websockets-13.1-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:80c421e07973a89fbdd93e6f2003c17d20b69010458d3a8e37fb47874bd67d51"}, - {file = "websockets-13.1-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:82d0ba76371769d6a4e56f7e83bb8e81846d17a6190971e38b5de108bde9b0d7"}, - {file = "websockets-13.1-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e9875a0143f07d74dc5e1ded1c4581f0d9f7ab86c78994e2ed9e95050073c94d"}, - {file = "websockets-13.1-pp38-pypy38_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a11e38ad8922c7961447f35c7b17bffa15de4d17c70abd07bfbe12d6faa3e027"}, - {file = "websockets-13.1-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:4059f790b6ae8768471cddb65d3c4fe4792b0ab48e154c9f0a04cefaabcd5978"}, - {file = "websockets-13.1-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:25c35bf84bf7c7369d247f0b8cfa157f989862c49104c5cf85cb5436a641d93e"}, - {file = "websockets-13.1-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:83f91d8a9bb404b8c2c41a707ac7f7f75b9442a0a876df295de27251a856ad09"}, - {file = "websockets-13.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7a43cfdcddd07f4ca2b1afb459824dd3c6d53a51410636a2c7fc97b9a8cf4842"}, - {file = "websockets-13.1-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:48a2ef1381632a2f0cb4efeff34efa97901c9fbc118e01951ad7cfc10601a9bb"}, - {file = "websockets-13.1-pp39-pypy39_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:459bf774c754c35dbb487360b12c5727adab887f1622b8aed5755880a21c4a20"}, - {file = "websockets-13.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:95858ca14a9f6fa8413d29e0a585b31b278388aa775b8a81fa24830123874678"}, - {file = "websockets-13.1-py3-none-any.whl", hash = "sha256:a9a396a6ad26130cdae92ae10c36af09d9bfe6cafe69670fd3b6da9b07b4044f"}, - {file = "websockets-13.1.tar.gz", hash = "sha256:a3b3366087c1bc0a2795111edcadddb8b3b59509d5db5d7ea3fdd69f954a8878"}, + {file = "websockets-14.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:064a72c0602c2d2c2586143561e0f179ef9b98e0825dc4a3d5cdf55a81898ed6"}, + {file = "websockets-14.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:9dc5a2726fd16c266d35838db086fa4e621bb049e3bbe498ab9d54ad5068f726"}, + {file = "websockets-14.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:1e541e4c8983b118a584c306070878e7f9670b7781e04184b6e05f9fc92e8a0e"}, + {file = "websockets-14.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:23b13edb4df2d4e5d6dc747d83e6b244e267a6615ede90f18ef13dfb2b6feb87"}, + {file = "websockets-14.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:288365a33049dae3065cdb2c2dd4b48df4b64839c565761c4f3f0c360460a561"}, + {file = "websockets-14.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:79e2494047826a56f2951b2ada9dc139d2c3aff63122e86953cafe64ac0fde75"}, + {file = "websockets-14.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:5a5b76b47b62de16d26439d362b18d71394ca4376eb2c8838352be64b27ba8af"}, + {file = "websockets-14.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:7ed4111f305770e35070e49fbb9fbf757a9b6c9a31bb86d352eb4031d4aa976f"}, + {file = "websockets-14.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:9af48a2f4cc5e2e34cf69969079865100e418c27caa26c1e3369efcc20c81e17"}, + {file = "websockets-14.0-cp310-cp310-win32.whl", hash = "sha256:a97c10043bf74d7667be69383312007d54a507fac8fa101be492cc91e279d94d"}, + {file = "websockets-14.0-cp310-cp310-win_amd64.whl", hash = "sha256:5f86250ee98f6098479936b7d596418b6e4c919dfa156508e9d6ac5f8bfbe764"}, + {file = "websockets-14.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:3c12e6c1331ee8833fcb565c033f7eb4cb5642af37cef81211c222b617b170df"}, + {file = "websockets-14.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:445a53bce8344e62df4ed9a22fdd1f06cad8e404ead64b2a1f19bd826c8dad1b"}, + {file = "websockets-14.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3e4be641fed120790241ae15fde27374a62cadaadcc0bd2b4ce35790bd284fb6"}, + {file = "websockets-14.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b886b6d14cd089396155e6beb2935268bf995057bf24c3e5fd609af55c584a03"}, + {file = "websockets-14.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a9b8a85d62709a86a9a55d4720502e88968483ee7f365bd852b75935dec04e0d"}, + {file = "websockets-14.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:08d62f438a591c016c5d4c79eaf9a8f7a85b6c3ea88793d676c00c930a41e775"}, + {file = "websockets-14.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:189e9f074f2a77f7cf54634797b29be28116ee564ece421c7653030a2cef48f0"}, + {file = "websockets-14.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:0b406f2387dbaf301996b7b2cf41519c1fbba7d5c9626406dd56f72075a60a00"}, + {file = "websockets-14.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:a3741f4394ba3d55a64949ee11ffdba19e2a2bdaa1319a96a7ab93bf8bd2b9b2"}, + {file = "websockets-14.0-cp311-cp311-win32.whl", hash = "sha256:b639ea88a46f4629645b398c9e7be0366c92e4910203a6314f78469f5e631dc5"}, + {file = "websockets-14.0-cp311-cp311-win_amd64.whl", hash = "sha256:715b238c1772ed28b98af8830df41c5d68941729e22384fe1433db495b1d5438"}, + {file = "websockets-14.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:f988f141a9be7a74d2e98d446b2f5411038bad14cdab80f9d1644b2329a71b48"}, + {file = "websockets-14.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7fd212e7022c70b4f8246dee4449dde30ff50c7e8e1d61ac87b7879579badd03"}, + {file = "websockets-14.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:4c06f014fd8fa3827e5fd03ec012945e2139901f261fcc401e0622476cad9c5c"}, + {file = "websockets-14.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6fad8f03dc976e710db785abf9deb76eb259312fb54d77b568c73f0162cef96e"}, + {file = "websockets-14.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6cff048a155024a580fee9f9a66b0ad9fc82683f6470c26eb76dd9280e6f459e"}, + {file = "websockets-14.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:56ec8098dcc47817c8aee8037165f0fe30fec8efe543c66e0924781a4bfcbdfd"}, + {file = "websockets-14.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:ee5fb667aec4ae723d40ada9854128df427b35b526c600cd352ca0240aad4dd7"}, + {file = "websockets-14.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:2752c98237057f27594a8393d498edd9db37e06abcfb99176d9cb6fb989dc883"}, + {file = "websockets-14.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e9ff528498d9e5c543bee388023ca91870678ac50724d675853ba85b4f0a459e"}, + {file = "websockets-14.0-cp312-cp312-win32.whl", hash = "sha256:8982909857b09220ee31d9a45699fce26f8e5b94a10efa7fe07004d4f4200a33"}, + {file = "websockets-14.0-cp312-cp312-win_amd64.whl", hash = "sha256:61b60c2a07b6d25f7ce8cc0101d55fb0f1af388bec1eddfe0181085c2206e7b0"}, + {file = "websockets-14.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:7cf000319db10a0cb5c7ce91bfd2a8699086b5cc0b5c5b83b92eec22a0448b2f"}, + {file = "websockets-14.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:0bae3caf386d418e83b62e8c1c4cec1b13348fac43e530b9894d6c7c02d921b5"}, + {file = "websockets-14.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:8eb46ac94d5c131336dc997a568f5579501958b14a507e6aa4840f6d856da980"}, + {file = "websockets-14.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:12c345585b1da70cd27a298b0b9a81aa18da7a690672f771b427db59c632d8aa"}, + {file = "websockets-14.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:81758da7c76b4e2ddabc4a98a51f3c3aca8585a6d3a8662b5061613303bd5f68"}, + {file = "websockets-14.0-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4eae86193fd667667f35367d292b912685cb22c3f9f1dd6deaa3fdd713ab5976"}, + {file = "websockets-14.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:7078dd0eac3a1dccf2c6f474004dbe8a4e936dbd19d37bbfb6efa70c923ae04e"}, + {file = "websockets-14.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:2a418d596536a470f6f8e94cbb1fde66fe65e03d68c403eee0f2198b129e139a"}, + {file = "websockets-14.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:7d66eeab61956e231f35659e6d5b66dc04a3d51e65f2b8f71862dc6a8ba710d1"}, + {file = "websockets-14.0-cp313-cp313-win32.whl", hash = "sha256:b24f7286a5c4e350284623cf708662f0881fe7bc1146c1a1fe7e6a9be01a8d6b"}, + {file = "websockets-14.0-cp313-cp313-win_amd64.whl", hash = "sha256:fb260539dd2b64e93c9f2c59caa70d36d2020fb8e26fa17f62459ad50ebf6c24"}, + {file = "websockets-14.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:0913596e0072202be8729dab05266398b72ee57c4232f48d52fe2a0370d0b53f"}, + {file = "websockets-14.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6f2e7710f3c468519f9d5b01a291c407f809f8f831e5a204b238e02447046d78"}, + {file = "websockets-14.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:0ae0e14729038208711d2e2f769280621c22cd253e3dac00f809fa38c6ccb79d"}, + {file = "websockets-14.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4875d1c3ab3d1d9a9d8485dc1f4c2aaa63947824af03301911ea58d1e881e096"}, + {file = "websockets-14.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:678990bc5a1e4fa36e18d340d439079a21e6b8d249848b7066cad1a6cbd34b82"}, + {file = "websockets-14.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bdaf3b31f8343dcc6c20d068c10eb29325dd70f5dc321ebb5fbeaa280436e70e"}, + {file = "websockets-14.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:633bbda2d30bc695900f6a07de4e5d92a4e8e8d0d8a536bb3c2051bee4dc3856"}, + {file = "websockets-14.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:1c4ca7cc5a02f909789dad259dffe61be4f38ffb26dc5e26ab2dca2c7d7c87de"}, + {file = "websockets-14.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:5ade11f4939b885303d28b53d512e96e1a8ea8fbebedd6fef3e2e1afe633cc2a"}, + {file = "websockets-14.0-cp39-cp39-win32.whl", hash = "sha256:281b5ab9514eb241e347a46367a2374cb60cf8f420c4283948aa188f05e7810c"}, + {file = "websockets-14.0-cp39-cp39-win_amd64.whl", hash = "sha256:72fe11675685412917363481b79c56e68175e62352f84ca4788ac264f9ea6ed0"}, + {file = "websockets-14.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:3f1a697262e28682222f18fae70eb0800dfa50c6eb96b0561c6beb83d6cf78ca"}, + {file = "websockets-14.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:1e0e543e0e81c55e68552bd3c081282721c710a6379a2a78e1ec793853479b25"}, + {file = "websockets-14.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2786c74cbcb0263fd541e4a075aa8c932bdcaa91e5bbb8649c65304799acdd64"}, + {file = "websockets-14.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:176b39547950ff3520728bd1eadd0fa02c68492a1fabca636bab7883dd390905"}, + {file = "websockets-14.0-pp310-pypy310_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:86626d560ceb9d846d128b9c7bd2d0f247dbb62fb49c386762d109583140bf48"}, + {file = "websockets-14.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:ca447967131023e98fcb4867f05cf8584adb424b9108180b2414745a6ff41c31"}, + {file = "websockets-14.0-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:c4eb304743ab285f8f057344d115259fbe31e42151b9aae7610db83d2a7379b1"}, + {file = "websockets-14.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:cc7dbe53276429b2ca511a04a3979ce27aa2088fdd28c119c6913dccdfd0e909"}, + {file = "websockets-14.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f6dd785f7a521189b1233d3c86c0b66fb73d4769a1d253ce5b31081c5946f05f"}, + {file = "websockets-14.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:77697c303b874daf1c76d4e167cd5d6871c26964bc189e4bdb40427067d53a86"}, + {file = "websockets-14.0-pp39-pypy39_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:20979614e4d7266f15018c154255d35dfb9fc828fdf6b4924166b6728fed359f"}, + {file = "websockets-14.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:3fb3d9e3940ea15b30404200e768e6111c3ee2956c60ceb001cae057961ab058"}, + {file = "websockets-14.0-py3-none-any.whl", hash = "sha256:1a3bca8cfb66614e23a65aa5d6b87190876ec6f3247094939f9db877db55319c"}, + {file = "websockets-14.0.tar.gz", hash = "sha256:be90aa6dab180fed523c0c10a6729ad16c9ba79067402d01a4d8aa7ce48d4084"}, ] [[package]] @@ -3985,13 +3866,13 @@ watchdog = ["watchdog (>=2.3)"] [[package]] name = "wheel" -version = "0.44.0" +version = "0.45.0" description = "A built-package format for Python" optional = false python-versions = ">=3.8" files = [ - {file = "wheel-0.44.0-py3-none-any.whl", hash = "sha256:2376a90c98cc337d18623527a97c31797bd02bad0033d41547043a1cbfbe448f"}, - {file = "wheel-0.44.0.tar.gz", hash = "sha256:a29c3f2817e95ab89aa4660681ad547c0e9547f20e75b0562fe7723c9a2a9d49"}, + {file = "wheel-0.45.0-py3-none-any.whl", hash = "sha256:52f0baa5e6522155090a09c6bd95718cc46956d1b51d537ea5454249edb671c7"}, + {file = "wheel-0.45.0.tar.gz", hash = "sha256:a57353941a3183b3d5365346b567a260a0602a0f8a635926a7dede41b94c674a"}, ] [package.extras] @@ -4174,4 +4055,4 @@ maco = ["maco"] [metadata] lock-version = "2.0" python-versions = ">=3.10, <4.0" -content-hash = "f283142fd57ad19b7a5cff077d93ffa6757dc781335284bf651d152d85a579e1" +content-hash = "e30ef8fa29edbb92827c59ef826a28a4bff54f9080c2b36f33f23afa05818f6a" diff --git a/pyproject.toml b/pyproject.toml index 0968fee45b0..60e5bbbe026 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -69,7 +69,7 @@ django-allauth = "0.54.0" # https://django-allauth.readthedocs.io/en/latest/con # bingraph = {git = "https://github.com/CAPESandbox/binGraph.git", rev = "552d1210ac6770f8b202d0d1fc4610cc14d878ec"} die-python = "0.1.0" psycopg2-binary = "^2.9.5" -ruff = "0.0.290" +ruff = ">=0.7.2" paramiko = "3.4.0" psutil = "5.9.8" # peepdf-3 = "4.0.0" @@ -88,7 +88,7 @@ gunicorn = "^22.0.0" channels = "^3.0.5" setproctitle = "1.3.2" -CAPE-parsers = "0.1.4" +CAPE-parsers = ">=0.1.7" maco = "1.1.8" [tool.poetry.extras] @@ -142,3 +142,7 @@ norecursedirs = "tests/zip_compound" [build-system] requires = ["poetry-core>=1.0.0"] build-backend = "poetry.core.masonry.api" + +[lint] +select = ["E", "F"] +ignore = ["E402","E501"] From a87305cec04bb94c71830842d94c05c46f3cbaf0 Mon Sep 17 00:00:00 2001 From: GitHub Actions Date: Tue, 12 Nov 2024 15:40:00 +0000 Subject: [PATCH 062/121] ci: Update requirements.txt --- requirements.txt | 319 +++++++++++++++-------------------------------- 1 file changed, 104 insertions(+), 215 deletions(-) diff --git a/requirements.txt b/requirements.txt index b6f463440e2..fadaa91b323 100644 --- a/requirements.txt +++ b/requirements.txt @@ -55,9 +55,9 @@ bs4==0.0.1 ; python_version >= "3.10" and python_version < "4.0" \ cachetools==5.5.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:02134e8439cdc2ffb62023ce1debca2944c3f289d66bb17ead3ab3dede74b292 \ --hash=sha256:2cc24fb4cbe39633fb7badd9db9ca6295d766d9c2995f245725a46715d050f2a -cape-parsers==0.1.4 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:00a0541d9947257cacb6485ab513dee46812a90c22883bcc8c5eef592ff8750f \ - --hash=sha256:4957cfd4c4215c550a27ca8d3dd87a60dd834fc6b7785cf0785d35ce04211e72 +cape-parsers==0.1.8 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:9f8957c8f153474c1e8e2688d0638b69da90ac729f67c1ff9ecb38d8214e3d8f \ + --hash=sha256:b86a663d426c9d60cc45c00da06bb374e64ca8fa5741931e34bfe22f77772ea8 capstone==4.0.2 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:0d65ffe8620920976ceadedc769f22318f6f150a592368d8a735612367ac8a1a \ --hash=sha256:2842913092c9b69fd903744bc1b87488e1451625460baac173056e1808ec1c66 \ @@ -1283,104 +1283,9 @@ pyyaml==6.0.2 ; python_version >= "3.10" and python_version < "4.0" \ pyzipper==0.3.5 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:6040069654dad040cf8708d4db78ce5829238e2091ad8006a47d97d6ffe275d6 \ --hash=sha256:e696e9d306427400e23e13a766c7614b64d9fc3316bdc71bbcc8f0070a14f150 -rat-king-parser==3.1.3 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:229c7d4565e7c0ea3e6a75a8252df9223286a26b77b2d449c2612b95c8406605 \ - --hash=sha256:cd662eb127c1bb85345a4460439608cfc87b82e833503b632d5ccc713eb49123 -regex==2024.9.11 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:01c2acb51f8a7d6494c8c5eafe3d8e06d76563d8a8a4643b37e9b2dd8a2ff623 \ - --hash=sha256:02087ea0a03b4af1ed6ebab2c54d7118127fee8d71b26398e8e4b05b78963199 \ - --hash=sha256:040562757795eeea356394a7fb13076ad4f99d3c62ab0f8bdfb21f99a1f85664 \ - --hash=sha256:042c55879cfeb21a8adacc84ea347721d3d83a159da6acdf1116859e2427c43f \ - --hash=sha256:079400a8269544b955ffa9e31f186f01d96829110a3bf79dc338e9910f794fca \ - --hash=sha256:07f45f287469039ffc2c53caf6803cd506eb5f5f637f1d4acb37a738f71dd066 \ - --hash=sha256:09d77559e80dcc9d24570da3745ab859a9cf91953062e4ab126ba9d5993688ca \ - --hash=sha256:0cbff728659ce4bbf4c30b2a1be040faafaa9eca6ecde40aaff86f7889f4ab39 \ - --hash=sha256:0e12c481ad92d129c78f13a2a3662317e46ee7ef96c94fd332e1c29131875b7d \ - --hash=sha256:0ea51dcc0835eea2ea31d66456210a4e01a076d820e9039b04ae8d17ac11dee6 \ - --hash=sha256:0ffbcf9221e04502fc35e54d1ce9567541979c3fdfb93d2c554f0ca583a19b35 \ - --hash=sha256:1494fa8725c285a81d01dc8c06b55287a1ee5e0e382d8413adc0a9197aac6408 \ - --hash=sha256:16e13a7929791ac1216afde26f712802e3df7bf0360b32e4914dca3ab8baeea5 \ - --hash=sha256:18406efb2f5a0e57e3a5881cd9354c1512d3bb4f5c45d96d110a66114d84d23a \ - --hash=sha256:18e707ce6c92d7282dfce370cd205098384b8ee21544e7cb29b8aab955b66fa9 \ - --hash=sha256:220e92a30b426daf23bb67a7962900ed4613589bab80382be09b48896d211e92 \ - --hash=sha256:23b30c62d0f16827f2ae9f2bb87619bc4fba2044911e2e6c2eb1af0161cdb766 \ - --hash=sha256:23f9985c8784e544d53fc2930fc1ac1a7319f5d5332d228437acc9f418f2f168 \ - --hash=sha256:297f54910247508e6e5cae669f2bc308985c60540a4edd1c77203ef19bfa63ca \ - --hash=sha256:2b08fce89fbd45664d3df6ad93e554b6c16933ffa9d55cb7e01182baaf971508 \ - --hash=sha256:2cce2449e5927a0bf084d346da6cd5eb016b2beca10d0013ab50e3c226ffc0df \ - --hash=sha256:313ea15e5ff2a8cbbad96ccef6be638393041b0a7863183c2d31e0c6116688cf \ - --hash=sha256:323c1f04be6b2968944d730e5c2091c8c89767903ecaa135203eec4565ed2b2b \ - --hash=sha256:35f4a6f96aa6cb3f2f7247027b07b15a374f0d5b912c0001418d1d55024d5cb4 \ - --hash=sha256:3b37fa423beefa44919e009745ccbf353d8c981516e807995b2bd11c2c77d268 \ - --hash=sha256:3ce4f1185db3fbde8ed8aa223fc9620f276c58de8b0d4f8cc86fd1360829edb6 \ - --hash=sha256:46989629904bad940bbec2106528140a218b4a36bb3042d8406980be1941429c \ - --hash=sha256:4838e24ee015101d9f901988001038f7f0d90dc0c3b115541a1365fb439add62 \ - --hash=sha256:49b0e06786ea663f933f3710a51e9385ce0cba0ea56b67107fd841a55d56a231 \ - --hash=sha256:4db21ece84dfeefc5d8a3863f101995de646c6cb0536952c321a2650aa202c36 \ - --hash=sha256:54c4a097b8bc5bb0dfc83ae498061d53ad7b5762e00f4adaa23bee22b012e6ba \ - --hash=sha256:54d9ff35d4515debf14bc27f1e3b38bfc453eff3220f5bce159642fa762fe5d4 \ - --hash=sha256:55b96e7ce3a69a8449a66984c268062fbaa0d8ae437b285428e12797baefce7e \ - --hash=sha256:57fdd2e0b2694ce6fc2e5ccf189789c3e2962916fb38779d3e3521ff8fe7a822 \ - --hash=sha256:587d4af3979376652010e400accc30404e6c16b7df574048ab1f581af82065e4 \ - --hash=sha256:5b513b6997a0b2f10e4fd3a1313568e373926e8c252bd76c960f96fd039cd28d \ - --hash=sha256:5ddcd9a179c0a6fa8add279a4444015acddcd7f232a49071ae57fa6e278f1f71 \ - --hash=sha256:6113c008a7780792efc80f9dfe10ba0cd043cbf8dc9a76ef757850f51b4edc50 \ - --hash=sha256:635a1d96665f84b292e401c3d62775851aedc31d4f8784117b3c68c4fcd4118d \ - --hash=sha256:64ce2799bd75039b480cc0360907c4fb2f50022f030bf9e7a8705b636e408fad \ - --hash=sha256:69dee6a020693d12a3cf892aba4808fe168d2a4cef368eb9bf74f5398bfd4ee8 \ - --hash=sha256:6a2644a93da36c784e546de579ec1806bfd2763ef47babc1b03d765fe560c9f8 \ - --hash=sha256:6b41e1adc61fa347662b09398e31ad446afadff932a24807d3ceb955ed865cc8 \ - --hash=sha256:6c188c307e8433bcb63dc1915022deb553b4203a70722fc542c363bf120a01fd \ - --hash=sha256:6edd623bae6a737f10ce853ea076f56f507fd7726bee96a41ee3d68d347e4d16 \ - --hash=sha256:73d6d2f64f4d894c96626a75578b0bf7d9e56dcda8c3d037a2118fdfe9b1c664 \ - --hash=sha256:7a22ccefd4db3f12b526eccb129390942fe874a3a9fdbdd24cf55773a1faab1a \ - --hash=sha256:7fb89ee5d106e4a7a51bce305ac4efb981536301895f7bdcf93ec92ae0d91c7f \ - --hash=sha256:846bc79ee753acf93aef4184c040d709940c9d001029ceb7b7a52747b80ed2dd \ - --hash=sha256:85ab7824093d8f10d44330fe1e6493f756f252d145323dd17ab6b48733ff6c0a \ - --hash=sha256:8dee5b4810a89447151999428fe096977346cf2f29f4d5e29609d2e19e0199c9 \ - --hash=sha256:8e5fb5f77c8745a60105403a774fe2c1759b71d3e7b4ca237a5e67ad066c7199 \ - --hash=sha256:98eeee2f2e63edae2181c886d7911ce502e1292794f4c5ee71e60e23e8d26b5d \ - --hash=sha256:9d4a76b96f398697fe01117093613166e6aa8195d63f1b4ec3f21ab637632963 \ - --hash=sha256:9e8719792ca63c6b8340380352c24dcb8cd7ec49dae36e963742a275dfae6009 \ - --hash=sha256:a0b2b80321c2ed3fcf0385ec9e51a12253c50f146fddb2abbb10f033fe3d049a \ - --hash=sha256:a4cc92bb6db56ab0c1cbd17294e14f5e9224f0cc6521167ef388332604e92679 \ - --hash=sha256:a738b937d512b30bf75995c0159c0ddf9eec0775c9d72ac0202076c72f24aa96 \ - --hash=sha256:a8f877c89719d759e52783f7fe6e1c67121076b87b40542966c02de5503ace42 \ - --hash=sha256:a906ed5e47a0ce5f04b2c981af1c9acf9e8696066900bf03b9d7879a6f679fc8 \ - --hash=sha256:ae2941333154baff9838e88aa71c1d84f4438189ecc6021a12c7573728b5838e \ - --hash=sha256:b0d0a6c64fcc4ef9c69bd5b3b3626cc3776520a1637d8abaa62b9edc147a58f7 \ - --hash=sha256:b5b029322e6e7b94fff16cd120ab35a253236a5f99a79fb04fda7ae71ca20ae8 \ - --hash=sha256:b7aaa315101c6567a9a45d2839322c51c8d6e81f67683d529512f5bcfb99c802 \ - --hash=sha256:be1c8ed48c4c4065ecb19d882a0ce1afe0745dfad8ce48c49586b90a55f02366 \ - --hash=sha256:c0256beda696edcf7d97ef16b2a33a8e5a875affd6fa6567b54f7c577b30a137 \ - --hash=sha256:c157bb447303070f256e084668b702073db99bbb61d44f85d811025fcf38f784 \ - --hash=sha256:c57d08ad67aba97af57a7263c2d9006d5c404d721c5f7542f077f109ec2a4a29 \ - --hash=sha256:c69ada171c2d0e97a4b5aa78fbb835e0ffbb6b13fc5da968c09811346564f0d3 \ - --hash=sha256:c94bb0a9f1db10a1d16c00880bdebd5f9faf267273b8f5bd1878126e0fbde771 \ - --hash=sha256:cb130fccd1a37ed894824b8c046321540263013da72745d755f2d35114b81a60 \ - --hash=sha256:ced479f601cd2f8ca1fd7b23925a7e0ad512a56d6e9476f79b8f381d9d37090a \ - --hash=sha256:d05ac6fa06959c4172eccd99a222e1fbf17b5670c4d596cb1e5cde99600674c4 \ - --hash=sha256:d552c78411f60b1fdaafd117a1fca2f02e562e309223b9d44b7de8be451ec5e0 \ - --hash=sha256:dd4490a33eb909ef5078ab20f5f000087afa2a4daa27b4c072ccb3cb3050ad84 \ - --hash=sha256:df5cbb1fbc74a8305b6065d4ade43b993be03dbe0f8b30032cced0d7740994bd \ - --hash=sha256:e28f9faeb14b6f23ac55bfbbfd3643f5c7c18ede093977f1df249f73fd22c7b1 \ - --hash=sha256:e464b467f1588e2c42d26814231edecbcfe77f5ac414d92cbf4e7b55b2c2a776 \ - --hash=sha256:e4c22e1ac1f1ec1e09f72e6c44d8f2244173db7eb9629cc3a346a8d7ccc31142 \ - --hash=sha256:e53b5fbab5d675aec9f0c501274c467c0f9a5d23696cfc94247e1fb56501ed89 \ - --hash=sha256:e93f1c331ca8e86fe877a48ad64e77882c0c4da0097f2212873a69bbfea95d0c \ - --hash=sha256:e997fd30430c57138adc06bba4c7c2968fb13d101e57dd5bb9355bf8ce3fa7e8 \ - --hash=sha256:e9a091b0550b3b0207784a7d6d0f1a00d1d1c8a11699c1a4d93db3fbefc3ad35 \ - --hash=sha256:eab4bb380f15e189d1313195b062a6aa908f5bd687a0ceccd47c8211e9cf0d4a \ - --hash=sha256:eb1ae19e64c14c7ec1995f40bd932448713d3c73509e82d8cd7744dc00e29e86 \ - --hash=sha256:ecea58b43a67b1b79805f1a0255730edaf5191ecef84dbc4cc85eb30bc8b63b9 \ - --hash=sha256:ee439691d8c23e76f9802c42a95cfeebf9d47cf4ffd06f18489122dbb0a7ad64 \ - --hash=sha256:eee9130eaad130649fd73e5cd92f60e55708952260ede70da64de420cdcad554 \ - --hash=sha256:f47cd43a5bfa48f86925fe26fbdd0a488ff15b62468abb5d2a1e092a4fb10e85 \ - --hash=sha256:f6fff13ef6b5f29221d6904aa816c34701462956aa72a77f1f151a8ec4f56aeb \ - --hash=sha256:f745ec09bc1b0bd15cfc73df6fa4f726dcc26bb16c23a03f9e3367d357eeedd0 \ - --hash=sha256:f8404bf61298bb6f8224bb9176c1424548ee1181130818fcd2cbffddc768bed8 \ - --hash=sha256:f9268774428ec173654985ce55fc6caf4c6d11ade0f6f914d48ef4719eb05ebb \ - --hash=sha256:faa3c142464efec496967359ca99696c896c591c56c53506bac1ad465f66e919 +rat-king-parser==3.1.5 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:0a2a97160cbad468df5149a28f1ee8aae6099206ffcd894dfadb43920c80bb11 \ + --hash=sha256:8bfccf381ce8647d66f54a46bbaca4d74765af206a37615c430ca5ac7526b213 requests-file==1.5.1 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:07d74208d3389d01c38ab89ef403af0cfec63957d53a0081d8eca738d0247d8e \ --hash=sha256:dfe5dae75c12481f68ba353183c53a65e6044c923e64c24b2209f6c7570ca953 @@ -1393,24 +1298,25 @@ requests==2.32.2 ; python_version >= "3.10" and python_version < "4.0" \ requests[security,socks]==2.32.2 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:dd951ff5ecf3e3b3aa26b40703ba77495dab41da839ae72ef3c8e5d8e2433289 \ --hash=sha256:fc06670dd0ed212426dfeb94fc1b983d917c4f9847c863f313c9dfaaffb7c23c -ruff==0.0.290 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:0e2b09ac4213b11a3520221083866a5816616f3ae9da123037b8ab275066fbac \ - --hash=sha256:150bf8050214cea5b990945b66433bf9a5e0cef395c9bc0f50569e7de7540c86 \ - --hash=sha256:1d9be6351b7889462912e0b8185a260c0219c35dfd920fb490c7f256f1d8313e \ - --hash=sha256:2ab41bc0ba359d3f715fc7b705bdeef19c0461351306b70a4e247f836b9350ed \ - --hash=sha256:35e3550d1d9f2157b0fcc77670f7bb59154f223bff281766e61bdd1dd854e0c5 \ - --hash=sha256:461fbd1fb9ca806d4e3d5c745a30e185f7cf3ca77293cdc17abb2f2a990ad3f7 \ - --hash=sha256:4ca6285aa77b3d966be32c9a3cd531655b3d4a0171e1f9bf26d66d0372186767 \ - --hash=sha256:75386ebc15fe5467248c039f5bf6a0cfe7bfc619ffbb8cd62406cd8811815fca \ - --hash=sha256:75cdc7fe32dcf33b7cec306707552dda54632ac29402775b9e212a3c16aad5e6 \ - --hash=sha256:949fecbc5467bb11b8db810a7fa53c7e02633856ee6bd1302b2f43adcd71b88d \ - --hash=sha256:982af5ec67cecd099e2ef5e238650407fb40d56304910102d054c109f390bf3c \ - --hash=sha256:ac93eadf07bc4ab4c48d8bb4e427bf0f58f3a9c578862eb85d99d704669f5da0 \ - --hash=sha256:ae5a92dfbdf1f0c689433c223f8dac0782c2b2584bd502dfdbc76475669f1ba1 \ - --hash=sha256:bbd37352cea4ee007c48a44c9bc45a21f7ba70a57edfe46842e346651e2b995a \ - --hash=sha256:d748c8bd97874f5751aed73e8dde379ce32d16338123d07c18b25c9a2796574a \ - --hash=sha256:eb07f37f7aecdbbc91d759c0c09870ce0fb3eed4025eebedf9c4b98c69abd527 \ - --hash=sha256:f1f49f5ec967fd5778813780b12a5650ab0ebcb9ddcca28d642c689b36920796 +ruff==0.7.3 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:10ebce7696afe4644e8c1a23b3cf8c0f2193a310c18387c06e583ae9ef284de2 \ + --hash=sha256:1713e2c5545863cdbfe2cbce21f69ffaf37b813bfd1fb3b90dc9a6f1963f5a8c \ + --hash=sha256:34f2339dc22687ec7e7002792d1f50712bf84a13d5152e75712ac08be565d344 \ + --hash=sha256:37d0b619546103274e7f62643d14e1adcbccb242efda4e4bdb9544d7764782e9 \ + --hash=sha256:3f36d56326b3aef8eeee150b700e519880d1aab92f471eefdef656fd57492aa2 \ + --hash=sha256:44eb93c2499a169d49fafd07bc62ac89b1bc800b197e50ff4633aed212569299 \ + --hash=sha256:4ba81a5f0c5478aa61674c5a2194de8b02652f17addf8dfc40c8937e6e7d79fc \ + --hash=sha256:588a9ff2fecf01025ed065fe28809cd5a53b43505f48b69a1ac7707b1b7e4088 \ + --hash=sha256:5d024301109a0007b78d57ab0ba190087b43dce852e552734ebf0b0b85e4fb16 \ + --hash=sha256:5d59f0c3ee4d1a6787614e7135b72e21024875266101142a09a61439cb6e38a5 \ + --hash=sha256:61b46049d6edc0e4317fb14b33bd693245281a3007288b68a3f5b74a22a0746d \ + --hash=sha256:6b6224af8b5e09772c2ecb8dc9f3f344c1aa48201c7f07e7315367f6dd90ac29 \ + --hash=sha256:6d0242ce53f3a576c35ee32d907475a8d569944c0407f91d207c8af5be5dae4e \ + --hash=sha256:7f3eff9961b5d2644bcf1616c606e93baa2d6b349e8aa8b035f654df252c8c67 \ + --hash=sha256:b8963cab06d130c4df2fd52c84e9f10d297826d2e8169ae0c798b6221be1d1d2 \ + --hash=sha256:c50f95a82b94421c964fae4c27c0242890a20fe67d203d127e84fbb8013855f5 \ + --hash=sha256:e1d1ba2e40b6e71a61b063354d04be669ab0d39c352461f3d789cac68b54a313 \ + --hash=sha256:fb397332a1879b9764a3455a0bb1087bda876c2db8aca3a3cbb67b3dbce8cda0 service-identity==24.2.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:6b047fbd8a84fd0bb0d55ebce4031e400562b9196e1e0d3e0fe2b8a59f6d4a85 \ --hash=sha256:b8683ba13f0d39c6cd5d625d2c5f65421d6d707b013b375c355751557cbe8e09 @@ -1555,12 +1461,12 @@ sqlalchemy==1.4.50 ; python_version >= "3.10" and python_version < "4.0" \ sqlparse==0.5.1 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:773dcbf9a5ab44a090f3441e2180efe2560220203dc2f8c0b0fa141e18b505e4 \ --hash=sha256:bb6b4df465655ef332548e24f08e205afc81b9ab86cb1c45657a7ff173a3a00e -tldextract==5.1.2 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:4dfc4c277b6b97fa053899fcdb892d2dc27295851ab5fac4e07797b6a21b2e46 \ - --hash=sha256:c9e17f756f05afb5abac04fe8f766e7e70f9fe387adb1859f0f52408ee060200 -tomli==2.0.2 ; python_version >= "3.10" and python_version < "3.11" \ - --hash=sha256:2ebe24485c53d303f690b0ec092806a085f07af5a5aa1464f3931eec36caaa38 \ - --hash=sha256:d46d457a85337051c36524bc5349dd91b1877838e2979ac5ced3e710ed8a60ed +tldextract==5.1.3 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:78de310cc2ca018692de5ddf320f9d6bd7c5cf857d0fd4f2175f0cdf4440ea75 \ + --hash=sha256:d43c7284c23f5dc8a42fd0fee2abede2ff74cc622674e4cb07f514ab3330c338 +tomli==2.1.0 ; python_version >= "3.10" and python_version < "3.11" \ + --hash=sha256:3f646cae2aec94e17d04973e4249548320197cfabdf130015d023de4b74d8ab8 \ + --hash=sha256:a5c57c3d1c56f5ccdf89f6523458f60ef716e210fc47c4cfb188c5ba473e0391 twisted[tls]==24.10.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:02951299672595fea0f70fa2d5f7b5e3d56836157eda68859a6ad6492d36756e \ --hash=sha256:67aa7c8aa94387385302acf44ade12967c747858c8bcce0f11d38077a11c5326 @@ -1713,99 +1619,82 @@ watchfiles==0.24.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:f83df90191d67af5a831da3a33dd7628b02a95450e168785586ed51e6d28943c \ --hash=sha256:fca9433a45f18b7c779d2bae7beeec4f740d28b788b117a48368d95a3233ed83 \ --hash=sha256:fd92bbaa2ecdb7864b7600dcdb6f2f1db6e0346ed425fbd01085be04c63f0b05 -websockets==13.1 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:004280a140f220c812e65f36944a9ca92d766b6cc4560be652a0a3883a79ed8a \ - --hash=sha256:035233b7531fb92a76beefcbf479504db8c72eb3bff41da55aecce3a0f729e54 \ - --hash=sha256:149e622dc48c10ccc3d2760e5f36753db9cacf3ad7bc7bbbfd7d9c819e286f23 \ - --hash=sha256:163e7277e1a0bd9fb3c8842a71661ad19c6aa7bb3d6678dc7f89b17fbcc4aeb7 \ - --hash=sha256:18503d2c5f3943e93819238bf20df71982d193f73dcecd26c94514f417f6b135 \ - --hash=sha256:1971e62d2caa443e57588e1d82d15f663b29ff9dfe7446d9964a4b6f12c1e700 \ - --hash=sha256:204e5107f43095012b00f1451374693267adbb832d29966a01ecc4ce1db26faf \ - --hash=sha256:2510c09d8e8df777177ee3d40cd35450dc169a81e747455cc4197e63f7e7bfe5 \ - --hash=sha256:25c35bf84bf7c7369d247f0b8cfa157f989862c49104c5cf85cb5436a641d93e \ - --hash=sha256:2f85cf4f2a1ba8f602298a853cec8526c2ca42a9a4b947ec236eaedb8f2dc80c \ - --hash=sha256:308e20f22c2c77f3f39caca508e765f8725020b84aa963474e18c59accbf4c02 \ - --hash=sha256:325b1ccdbf5e5725fdcb1b0e9ad4d2545056479d0eee392c291c1bf76206435a \ - --hash=sha256:327b74e915cf13c5931334c61e1a41040e365d380f812513a255aa804b183418 \ - --hash=sha256:346bee67a65f189e0e33f520f253d5147ab76ae42493804319b5716e46dddf0f \ - --hash=sha256:38377f8b0cdeee97c552d20cf1865695fcd56aba155ad1b4ca8779a5b6ef4ac3 \ - --hash=sha256:3c78383585f47ccb0fcf186dcb8a43f5438bd7d8f47d69e0b56f71bf431a0a68 \ - --hash=sha256:4059f790b6ae8768471cddb65d3c4fe4792b0ab48e154c9f0a04cefaabcd5978 \ - --hash=sha256:459bf774c754c35dbb487360b12c5727adab887f1622b8aed5755880a21c4a20 \ - --hash=sha256:463e1c6ec853202dd3657f156123d6b4dad0c546ea2e2e38be2b3f7c5b8e7295 \ - --hash=sha256:4676df3fe46956fbb0437d8800cd5f2b6d41143b6e7e842e60554398432cf29b \ - --hash=sha256:485307243237328c022bc908b90e4457d0daa8b5cf4b3723fd3c4a8012fce4c6 \ - --hash=sha256:48a2ef1381632a2f0cb4efeff34efa97901c9fbc118e01951ad7cfc10601a9bb \ - --hash=sha256:4b889dbd1342820cc210ba44307cf75ae5f2f96226c0038094455a96e64fb07a \ - --hash=sha256:586a356928692c1fed0eca68b4d1c2cbbd1ca2acf2ac7e7ebd3b9052582deefa \ - --hash=sha256:58cf7e75dbf7e566088b07e36ea2e3e2bd5676e22216e4cad108d4df4a7402a0 \ - --hash=sha256:5993260f483d05a9737073be197371940c01b257cc45ae3f1d5d7adb371b266a \ - --hash=sha256:5dd6da9bec02735931fccec99d97c29f47cc61f644264eb995ad6c0c27667238 \ - --hash=sha256:5f2e75431f8dc4a47f31565a6e1355fb4f2ecaa99d6b89737527ea917066e26c \ - --hash=sha256:5f9fee94ebafbc3117c30be1844ed01a3b177bb6e39088bc6b2fa1dc15572084 \ - --hash=sha256:61fc0dfcda609cda0fc9fe7977694c0c59cf9d749fbb17f4e9483929e3c48a19 \ - --hash=sha256:624459daabeb310d3815b276c1adef475b3e6804abaf2d9d2c061c319f7f187d \ - --hash=sha256:62d516c325e6540e8a57b94abefc3459d7dab8ce52ac75c96cad5549e187e3a7 \ - --hash=sha256:6548f29b0e401eea2b967b2fdc1c7c7b5ebb3eeb470ed23a54cd45ef078a0db9 \ - --hash=sha256:6d2aad13a200e5934f5a6767492fb07151e1de1d6079c003ab31e1823733ae79 \ - --hash=sha256:6d6855bbe70119872c05107e38fbc7f96b1d8cb047d95c2c50869a46c65a8e96 \ - --hash=sha256:70c5be9f416aa72aab7a2a76c90ae0a4fe2755c1816c153c1a2bcc3333ce4ce6 \ - --hash=sha256:730f42125ccb14602f455155084f978bd9e8e57e89b569b4d7f0f0c17a448ffe \ - --hash=sha256:7a43cfdcddd07f4ca2b1afb459824dd3c6d53a51410636a2c7fc97b9a8cf4842 \ - --hash=sha256:7bd6abf1e070a6b72bfeb71049d6ad286852e285f146682bf30d0296f5fbadfa \ - --hash=sha256:7c1e90228c2f5cdde263253fa5db63e6653f1c00e7ec64108065a0b9713fa1b3 \ - --hash=sha256:7c65ffa900e7cc958cd088b9a9157a8141c991f8c53d11087e6fb7277a03f81d \ - --hash=sha256:80c421e07973a89fbdd93e6f2003c17d20b69010458d3a8e37fb47874bd67d51 \ - --hash=sha256:82d0ba76371769d6a4e56f7e83bb8e81846d17a6190971e38b5de108bde9b0d7 \ - --hash=sha256:83f91d8a9bb404b8c2c41a707ac7f7f75b9442a0a876df295de27251a856ad09 \ - --hash=sha256:87c6e35319b46b99e168eb98472d6c7d8634ee37750d7693656dc766395df096 \ - --hash=sha256:8d23b88b9388ed85c6faf0e74d8dec4f4d3baf3ecf20a65a47b836d56260d4b9 \ - --hash=sha256:9156c45750b37337f7b0b00e6248991a047be4aa44554c9886fe6bdd605aab3b \ - --hash=sha256:91a0fa841646320ec0d3accdff5b757b06e2e5c86ba32af2e0815c96c7a603c5 \ - --hash=sha256:95858ca14a9f6fa8413d29e0a585b31b278388aa775b8a81fa24830123874678 \ - --hash=sha256:95df24ca1e1bd93bbca51d94dd049a984609687cb2fb08a7f2c56ac84e9816ea \ - --hash=sha256:9b37c184f8b976f0c0a231a5f3d6efe10807d41ccbe4488df8c74174805eea7d \ - --hash=sha256:9b6f347deb3dcfbfde1c20baa21c2ac0751afaa73e64e5b693bb2b848efeaa49 \ - --hash=sha256:9d75baf00138f80b48f1eac72ad1535aac0b6461265a0bcad391fc5aba875cfc \ - --hash=sha256:9ef8aa8bdbac47f4968a5d66462a2a0935d044bf35c0e5a8af152d58516dbeb5 \ - --hash=sha256:a11e38ad8922c7961447f35c7b17bffa15de4d17c70abd07bfbe12d6faa3e027 \ - --hash=sha256:a1b54689e38d1279a51d11e3467dd2f3a50f5f2e879012ce8f2d6943f00e83f0 \ - --hash=sha256:a3b3366087c1bc0a2795111edcadddb8b3b59509d5db5d7ea3fdd69f954a8878 \ - --hash=sha256:a569eb1b05d72f9bce2ebd28a1ce2054311b66677fcd46cf36204ad23acead8c \ - --hash=sha256:a7affedeb43a70351bb811dadf49493c9cfd1ed94c9c70095fd177e9cc1541fa \ - --hash=sha256:a9a396a6ad26130cdae92ae10c36af09d9bfe6cafe69670fd3b6da9b07b4044f \ - --hash=sha256:a9ab1e71d3d2e54a0aa646ab6d4eebfaa5f416fe78dfe4da2839525dc5d765c6 \ - --hash=sha256:a9cd1af7e18e5221d2878378fbc287a14cd527fdd5939ed56a18df8a31136bb2 \ - --hash=sha256:a9dcaf8b0cc72a392760bb8755922c03e17a5a54e08cca58e8b74f6902b433cf \ - --hash=sha256:b9d7439d7fab4dce00570bb906875734df13d9faa4b48e261c440a5fec6d9708 \ - --hash=sha256:bcc03c8b72267e97b49149e4863d57c2d77f13fae12066622dc78fe322490fe6 \ - --hash=sha256:c11d4d16e133f6df8916cc5b7e3e96ee4c44c936717d684a94f48f82edb7c92f \ - --hash=sha256:c1dca61c6db1166c48b95198c0b7d9c990b30c756fc2923cc66f68d17dc558fd \ - --hash=sha256:c518e84bb59c2baae725accd355c8dc517b4a3ed8db88b4bc93c78dae2974bf2 \ - --hash=sha256:c7934fd0e920e70468e676fe7f1b7261c1efa0d6c037c6722278ca0228ad9d0d \ - --hash=sha256:c7e72ce6bda6fb9409cc1e8164dd41d7c91466fb599eb047cfda72fe758a34a7 \ - --hash=sha256:c90d6dec6be2c7d03378a574de87af9b1efea77d0c52a8301dd831ece938452f \ - --hash=sha256:ceec59f59d092c5007e815def4ebb80c2de330e9588e101cf8bd94c143ec78a5 \ - --hash=sha256:cf1781ef73c073e6b0f90af841aaf98501f975d306bbf6221683dd594ccc52b6 \ - --hash=sha256:d04f13a1d75cb2b8382bdc16ae6fa58c97337253826dfe136195b7f89f661557 \ - --hash=sha256:d6d300f8ec35c24025ceb9b9019ae9040c1ab2f01cddc2bcc0b518af31c75c14 \ - --hash=sha256:d8dbb1bf0c0a4ae8b40bdc9be7f644e2f3fb4e8a9aca7145bfa510d4a374eeb7 \ - --hash=sha256:de58647e3f9c42f13f90ac7e5f58900c80a39019848c5547bc691693098ae1bd \ - --hash=sha256:deeb929efe52bed518f6eb2ddc00cc496366a14c726005726ad62c2dd9017a3c \ - --hash=sha256:df01aea34b6e9e33572c35cd16bae5a47785e7d5c8cb2b54b2acdb9678315a17 \ - --hash=sha256:e2620453c075abeb0daa949a292e19f56de518988e079c36478bacf9546ced23 \ - --hash=sha256:e4450fc83a3df53dec45922b576e91e94f5578d06436871dce3a6be38e40f5db \ - --hash=sha256:e54affdeb21026329fb0744ad187cf812f7d3c2aa702a5edb562b325191fcab6 \ - --hash=sha256:e9875a0143f07d74dc5e1ded1c4581f0d9f7ab86c78994e2ed9e95050073c94d \ - --hash=sha256:f1c3cf67185543730888b20682fb186fc8d0fa6f07ccc3ef4390831ab4b388d9 \ - --hash=sha256:f48c749857f8fb598fb890a75f540e3221d0976ed0bf879cf3c7eef34151acee \ - --hash=sha256:f779498eeec470295a2b1a5d97aa1bc9814ecd25e1eb637bd9d1c73a327387f6 +websockets==14.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:064a72c0602c2d2c2586143561e0f179ef9b98e0825dc4a3d5cdf55a81898ed6 \ + --hash=sha256:08d62f438a591c016c5d4c79eaf9a8f7a85b6c3ea88793d676c00c930a41e775 \ + --hash=sha256:0913596e0072202be8729dab05266398b72ee57c4232f48d52fe2a0370d0b53f \ + --hash=sha256:0ae0e14729038208711d2e2f769280621c22cd253e3dac00f809fa38c6ccb79d \ + --hash=sha256:0b406f2387dbaf301996b7b2cf41519c1fbba7d5c9626406dd56f72075a60a00 \ + --hash=sha256:0bae3caf386d418e83b62e8c1c4cec1b13348fac43e530b9894d6c7c02d921b5 \ + --hash=sha256:12c345585b1da70cd27a298b0b9a81aa18da7a690672f771b427db59c632d8aa \ + --hash=sha256:176b39547950ff3520728bd1eadd0fa02c68492a1fabca636bab7883dd390905 \ + --hash=sha256:189e9f074f2a77f7cf54634797b29be28116ee564ece421c7653030a2cef48f0 \ + --hash=sha256:1a3bca8cfb66614e23a65aa5d6b87190876ec6f3247094939f9db877db55319c \ + --hash=sha256:1c4ca7cc5a02f909789dad259dffe61be4f38ffb26dc5e26ab2dca2c7d7c87de \ + --hash=sha256:1e0e543e0e81c55e68552bd3c081282721c710a6379a2a78e1ec793853479b25 \ + --hash=sha256:1e541e4c8983b118a584c306070878e7f9670b7781e04184b6e05f9fc92e8a0e \ + --hash=sha256:20979614e4d7266f15018c154255d35dfb9fc828fdf6b4924166b6728fed359f \ + --hash=sha256:23b13edb4df2d4e5d6dc747d83e6b244e267a6615ede90f18ef13dfb2b6feb87 \ + --hash=sha256:2752c98237057f27594a8393d498edd9db37e06abcfb99176d9cb6fb989dc883 \ + --hash=sha256:2786c74cbcb0263fd541e4a075aa8c932bdcaa91e5bbb8649c65304799acdd64 \ + --hash=sha256:281b5ab9514eb241e347a46367a2374cb60cf8f420c4283948aa188f05e7810c \ + --hash=sha256:288365a33049dae3065cdb2c2dd4b48df4b64839c565761c4f3f0c360460a561 \ + --hash=sha256:2a418d596536a470f6f8e94cbb1fde66fe65e03d68c403eee0f2198b129e139a \ + --hash=sha256:3c12e6c1331ee8833fcb565c033f7eb4cb5642af37cef81211c222b617b170df \ + --hash=sha256:3e4be641fed120790241ae15fde27374a62cadaadcc0bd2b4ce35790bd284fb6 \ + --hash=sha256:3f1a697262e28682222f18fae70eb0800dfa50c6eb96b0561c6beb83d6cf78ca \ + --hash=sha256:3fb3d9e3940ea15b30404200e768e6111c3ee2956c60ceb001cae057961ab058 \ + --hash=sha256:445a53bce8344e62df4ed9a22fdd1f06cad8e404ead64b2a1f19bd826c8dad1b \ + --hash=sha256:4875d1c3ab3d1d9a9d8485dc1f4c2aaa63947824af03301911ea58d1e881e096 \ + --hash=sha256:4c06f014fd8fa3827e5fd03ec012945e2139901f261fcc401e0622476cad9c5c \ + --hash=sha256:4eae86193fd667667f35367d292b912685cb22c3f9f1dd6deaa3fdd713ab5976 \ + --hash=sha256:56ec8098dcc47817c8aee8037165f0fe30fec8efe543c66e0924781a4bfcbdfd \ + --hash=sha256:5a5b76b47b62de16d26439d362b18d71394ca4376eb2c8838352be64b27ba8af \ + --hash=sha256:5ade11f4939b885303d28b53d512e96e1a8ea8fbebedd6fef3e2e1afe633cc2a \ + --hash=sha256:5f86250ee98f6098479936b7d596418b6e4c919dfa156508e9d6ac5f8bfbe764 \ + --hash=sha256:61b60c2a07b6d25f7ce8cc0101d55fb0f1af388bec1eddfe0181085c2206e7b0 \ + --hash=sha256:633bbda2d30bc695900f6a07de4e5d92a4e8e8d0d8a536bb3c2051bee4dc3856 \ + --hash=sha256:678990bc5a1e4fa36e18d340d439079a21e6b8d249848b7066cad1a6cbd34b82 \ + --hash=sha256:6cff048a155024a580fee9f9a66b0ad9fc82683f6470c26eb76dd9280e6f459e \ + --hash=sha256:6f2e7710f3c468519f9d5b01a291c407f809f8f831e5a204b238e02447046d78 \ + --hash=sha256:6fad8f03dc976e710db785abf9deb76eb259312fb54d77b568c73f0162cef96e \ + --hash=sha256:7078dd0eac3a1dccf2c6f474004dbe8a4e936dbd19d37bbfb6efa70c923ae04e \ + --hash=sha256:715b238c1772ed28b98af8830df41c5d68941729e22384fe1433db495b1d5438 \ + --hash=sha256:72fe11675685412917363481b79c56e68175e62352f84ca4788ac264f9ea6ed0 \ + --hash=sha256:77697c303b874daf1c76d4e167cd5d6871c26964bc189e4bdb40427067d53a86 \ + --hash=sha256:79e2494047826a56f2951b2ada9dc139d2c3aff63122e86953cafe64ac0fde75 \ + --hash=sha256:7cf000319db10a0cb5c7ce91bfd2a8699086b5cc0b5c5b83b92eec22a0448b2f \ + --hash=sha256:7d66eeab61956e231f35659e6d5b66dc04a3d51e65f2b8f71862dc6a8ba710d1 \ + --hash=sha256:7ed4111f305770e35070e49fbb9fbf757a9b6c9a31bb86d352eb4031d4aa976f \ + --hash=sha256:7fd212e7022c70b4f8246dee4449dde30ff50c7e8e1d61ac87b7879579badd03 \ + --hash=sha256:81758da7c76b4e2ddabc4a98a51f3c3aca8585a6d3a8662b5061613303bd5f68 \ + --hash=sha256:86626d560ceb9d846d128b9c7bd2d0f247dbb62fb49c386762d109583140bf48 \ + --hash=sha256:8982909857b09220ee31d9a45699fce26f8e5b94a10efa7fe07004d4f4200a33 \ + --hash=sha256:8eb46ac94d5c131336dc997a568f5579501958b14a507e6aa4840f6d856da980 \ + --hash=sha256:9af48a2f4cc5e2e34cf69969079865100e418c27caa26c1e3369efcc20c81e17 \ + --hash=sha256:9dc5a2726fd16c266d35838db086fa4e621bb049e3bbe498ab9d54ad5068f726 \ + --hash=sha256:a3741f4394ba3d55a64949ee11ffdba19e2a2bdaa1319a96a7ab93bf8bd2b9b2 \ + --hash=sha256:a97c10043bf74d7667be69383312007d54a507fac8fa101be492cc91e279d94d \ + --hash=sha256:a9b8a85d62709a86a9a55d4720502e88968483ee7f365bd852b75935dec04e0d \ + --hash=sha256:b24f7286a5c4e350284623cf708662f0881fe7bc1146c1a1fe7e6a9be01a8d6b \ + --hash=sha256:b639ea88a46f4629645b398c9e7be0366c92e4910203a6314f78469f5e631dc5 \ + --hash=sha256:b886b6d14cd089396155e6beb2935268bf995057bf24c3e5fd609af55c584a03 \ + --hash=sha256:bdaf3b31f8343dcc6c20d068c10eb29325dd70f5dc321ebb5fbeaa280436e70e \ + --hash=sha256:be90aa6dab180fed523c0c10a6729ad16c9ba79067402d01a4d8aa7ce48d4084 \ + --hash=sha256:c4eb304743ab285f8f057344d115259fbe31e42151b9aae7610db83d2a7379b1 \ + --hash=sha256:ca447967131023e98fcb4867f05cf8584adb424b9108180b2414745a6ff41c31 \ + --hash=sha256:cc7dbe53276429b2ca511a04a3979ce27aa2088fdd28c119c6913dccdfd0e909 \ + --hash=sha256:e9ff528498d9e5c543bee388023ca91870678ac50724d675853ba85b4f0a459e \ + --hash=sha256:ee5fb667aec4ae723d40ada9854128df427b35b526c600cd352ca0240aad4dd7 \ + --hash=sha256:f6dd785f7a521189b1233d3c86c0b66fb73d4769a1d253ce5b31081c5946f05f \ + --hash=sha256:f988f141a9be7a74d2e98d446b2f5411038bad14cdab80f9d1644b2329a71b48 \ + --hash=sha256:fb260539dd2b64e93c9f2c59caa70d36d2020fb8e26fa17f62459ad50ebf6c24 werkzeug==3.0.6 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:1bc0c2310d2fbb07b1dd1105eba2f7af72f322e1e455f2f93c993bee8c8a5f17 \ --hash=sha256:a8dd59d4de28ca70471a34cba79bed5f7ef2e036a76b3ab0835474246eb41f8d -wheel==0.44.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:2376a90c98cc337d18623527a97c31797bd02bad0033d41547043a1cbfbe448f \ - --hash=sha256:a29c3f2817e95ab89aa4660681ad547c0e9547f20e75b0562fe7723c9a2a9d49 +wheel==0.45.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:52f0baa5e6522155090a09c6bd95718cc46956d1b51d537ea5454249edb671c7 \ + --hash=sha256:a57353941a3183b3d5365346b567a260a0602a0f8a635926a7dede41b94c674a win-unicode-console==0.5 ; platform_system == "Windows" and platform_python_implementation != "PyPy" and python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:d4142d4d56d46f449d6f00536a73625a871cba040f0bc1a2e305a04578f07d1e yara-python==4.5.1 ; python_version >= "3.10" and python_version < "4.0" \ From 9fbb0defeaf5c4d20810613bb6db624d852e5a59 Mon Sep 17 00:00:00 2001 From: doomedraven Date: Wed, 13 Nov 2024 15:15:25 +0100 Subject: [PATCH 063/121] rewrite selfextract --- .../common/integrations/file_extra_info.py | 12 +- lib/cuckoo/common/integrations/parse_rdp.py | 145 ++++++++++++++---- lib/cuckoo/common/web_utils.py | 11 +- .../analysis/generic/_file_info.html | 21 +-- 4 files changed, 137 insertions(+), 52 deletions(-) diff --git a/lib/cuckoo/common/integrations/file_extra_info.py b/lib/cuckoo/common/integrations/file_extra_info.py index c0a4b48219c..972eca864ce 100644 --- a/lib/cuckoo/common/integrations/file_extra_info.py +++ b/lib/cuckoo/common/integrations/file_extra_info.py @@ -501,13 +501,11 @@ def generic_file_extractors( log.debug("Files already extracted from %s by %s. Also extracted with %s", file, old_tool_name, new_tool_name) continue metadata = _extracted_files_metadata(tempdir, destination_folder, files=extracted_files, results=results) - data_dictionary.update( - { - "extracted_files": metadata, - "extracted_files_tool": new_tool_name, - "extracted_files_time": func_result["took_seconds"], - } - ) + data_dictionary.setdefault("selfextract", {}) + data_dictionary["selfextract"][new_tool_name] = { + "extracted_files": metadata, + "extracted_files_time": func_result["took_seconds"], + } finally: if tempdir: # ToDo doesn't work diff --git a/lib/cuckoo/common/integrations/parse_rdp.py b/lib/cuckoo/common/integrations/parse_rdp.py index 82b04ea6142..b900e01a568 100644 --- a/lib/cuckoo/common/integrations/parse_rdp.py +++ b/lib/cuckoo/common/integrations/parse_rdp.py @@ -1,15 +1,25 @@ -# From https://github.com/wmetcalf/rdp_holiday - import argparse import base64 +import datetime import json +import logging import sys +from contextlib import suppress from hashlib import sha1, sha256 from struct import unpack -from cryptography.hazmat.primitives import hashes -from cryptography.hazmat.primitives.serialization import pkcs7 - +MISSED_DEPS = False +try: + import mscerts + from asn1crypto import pem, x509 + from certvalidator import CertificateValidator, ValidationContext + from cryptography import x509 as cx509 + from cryptography.hazmat.primitives import hashes, serialization + from cryptography.hazmat.primitives.serialization import pkcs7 + from cryptography.x509.oid import ExtensionOID +except ImportError: + print("pip3 install certvalidator asn1crypto mscerts") + MISSED_DEPS = True try: import re2 as re except ImportError: @@ -59,10 +69,57 @@ "signscope": re.compile(r"signscope\s*:\s*s\s*:\s*(.*)", re.I), } +log = logging.getLogger() + + +def validate_sig(hostname, alternate_faddress, pkcs7_certificates): + sign_data = { + "can_sign": False, + "usage_error": "", + "valid": False, + "validation_errors": [], + "general_error": "", + "main_valid": False, + "alt_valid": False, + } + if MISSED_DEPS: + return sign_data + try: + ca_bundle_path = mscerts.where() + trust_roots = [] + with open(ca_bundle_path, "rb") as f: + pem_data = f.read() + for _, _, der_bytes in pem.unarmor(pem_data, multiple=True): + trust_roots.append(der_bytes) + certs = [x509.Certificate.load(cert.public_bytes(serialization.Encoding.DER)) for cert in pkcs7_certificates] + context = ValidationContext(trust_roots=trust_roots) + main_cert = certs[0] + validator = CertificateValidator(main_cert, intermediate_certs=certs[1:], validation_context=context) + try: + validator.validate_usage({"digital_signature"}) + sign_data["can_sign"] = True + except Exception as e: + sign_data["usage_error"] = f"{e}" + try: + validator.validate_tls(hostname) + sign_data["main_valid"] = True + except Exception as e: + sign_data["validation_errors"].append(f"{e}") + if alternate_faddress: + try: + validator.validate_tls(alternate_faddress) + sign_data["alt_valid"] = True + except Exception as e: + sign_data["validation_errors"].append(f"{e}") + if sign_data["main_valid"] or sign_data["alt_valid"]: + sign_data["valid"] = True + except Exception as e: + sign_data["general_error"] = f"{e}" + return sign_data + def parse_rdp_file(file_path): rdp_properties = {} - try: content = "" encoding = "utf-8" @@ -97,35 +154,61 @@ def parse_rdp_file(file_path): "full_address is a required field but is not in parsed Properties what sort of nonsense are you trying to feed me?" ) return rdp_properties - - if "signature" in rdp_properties: + rdp_properties["signscope_but_missing_sig"] = False + if "signscope" in rdp_properties and "signature" not in rdp_properties: + rdp_properties["signscope_but_missing_sig"] = True + elif "signature" in rdp_properties and "signscope" in rdp_properties: + rdp_properties["certificate_truncated_or_invalid"] = False signature_base64 = rdp_properties["signature"] - signature_bytes = base64.b64decode(signature_base64.replace("\n", "").replace("\r", "")) - - size_bytes = signature_bytes[8:12] - data_size = unpack("