emsign-g3-distrust 0.2.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- emsign_g3/__init__.py +3 -0
- emsign_g3/cli.py +79 -0
- emsign_g3/data/certs/EMDVTLSCAG3B.pem +21 -0
- emsign_g3/data/certs/EMDVTLSCAG3C.pem +21 -0
- emsign_g3/data/certs/EMEVTLSCAG3B.pem +21 -0
- emsign_g3/data/certs/EMEVTLSCAG3C.pem +21 -0
- emsign_g3/data/certs/EMOVCSCAG3B.pem +20 -0
- emsign_g3/data/certs/EMOVCSCAG3C.pem +20 -0
- emsign_g3/data/certs/EMOVTLSCAG3B.pem +21 -0
- emsign_g3/data/certs/EMOVTLSCAG3C.pem +21 -0
- emsign_g3/data/indicators.csv +12 -0
- emsign_g3/distrust.py +202 -0
- emsign_g3/elastic.py +71 -0
- emsign_g3/export.py +187 -0
- emsign_g3/indicators.py +73 -0
- emsign_g3/paths.py +78 -0
- emsign_g3/scan.py +248 -0
- emsign_g3/siem_artifacts.py +58 -0
- emsign_g3/sigma.py +114 -0
- emsign_g3_distrust-0.2.0.dist-info/METADATA +182 -0
- emsign_g3_distrust-0.2.0.dist-info/RECORD +25 -0
- emsign_g3_distrust-0.2.0.dist-info/WHEEL +5 -0
- emsign_g3_distrust-0.2.0.dist-info/entry_points.txt +2 -0
- emsign_g3_distrust-0.2.0.dist-info/licenses/LICENSE +21 -0
- emsign_g3_distrust-0.2.0.dist-info/top_level.txt +1 -0
emsign_g3/__init__.py
ADDED
emsign_g3/cli.py
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
"""Unified CLI for emsign-g3 distrust tooling."""
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
import argparse
|
|
5
|
+
|
|
6
|
+
from emsign_g3.distrust import run_distrust
|
|
7
|
+
from emsign_g3.export import run_export
|
|
8
|
+
from emsign_g3.paths import default_certs_dir, indicators_csv_path
|
|
9
|
+
from emsign_g3.scan import run_scan
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def main(argv: list[str] | None = None) -> int:
|
|
13
|
+
parser = argparse.ArgumentParser(
|
|
14
|
+
prog="emsign-g3",
|
|
15
|
+
description="Detect and deny compromised eMudhra/emSign G3 intermediates (Bug 2083449).",
|
|
16
|
+
)
|
|
17
|
+
sub = parser.add_subparsers(dest="command", required=True)
|
|
18
|
+
|
|
19
|
+
scan_p = sub.add_parser("scan", help="inventory trust stores (read-only)")
|
|
20
|
+
scan_p.add_argument("--json", action="store_true", help="machine-readable output")
|
|
21
|
+
|
|
22
|
+
dist_p = sub.add_parser("distrust", help="plan or apply intermediate blocklist")
|
|
23
|
+
dist_p.add_argument("--apply", action="store_true", help="execute (default: dry run)")
|
|
24
|
+
dist_p.add_argument("--undo", action="store_true", help="roll back instead of distrust")
|
|
25
|
+
dist_p.add_argument(
|
|
26
|
+
"--certs-dir",
|
|
27
|
+
default=None,
|
|
28
|
+
help=f"directory with eight verified PEMs (default: {default_certs_dir()})",
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
exp_p = sub.add_parser("export-indicators", help="SIEM/SOAR indicator bundle")
|
|
32
|
+
exp_p.add_argument("--csv", default=None, help="path to indicators.csv")
|
|
33
|
+
exp_p.add_argument(
|
|
34
|
+
"--format",
|
|
35
|
+
choices=("json", "ndjson", "sigma", "elastic-kql"),
|
|
36
|
+
default="json",
|
|
37
|
+
help="output format (default: json)",
|
|
38
|
+
)
|
|
39
|
+
exp_p.add_argument(
|
|
40
|
+
"--ndjson",
|
|
41
|
+
action="store_true",
|
|
42
|
+
help="shorthand for --format ndjson (deprecated)",
|
|
43
|
+
)
|
|
44
|
+
exp_p.add_argument("--verify", action="store_true", help="verify PEMs match CSV")
|
|
45
|
+
exp_p.add_argument("--certs-dir", default=None, help="PEM directory for --verify")
|
|
46
|
+
exp_p.add_argument(
|
|
47
|
+
"--output-dir",
|
|
48
|
+
default=None,
|
|
49
|
+
help="write --format sigma or elastic-kql files to this directory",
|
|
50
|
+
)
|
|
51
|
+
exp_p.add_argument(
|
|
52
|
+
"--check-committed-rules",
|
|
53
|
+
action="store_true",
|
|
54
|
+
help="verify rules/sigma and rules/elastic match generators",
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
args = parser.parse_args(argv)
|
|
58
|
+
|
|
59
|
+
if args.command == "scan":
|
|
60
|
+
return run_scan(as_json=args.json)
|
|
61
|
+
if args.command == "distrust":
|
|
62
|
+
return run_distrust(apply=args.apply, undo=args.undo, certs_dir=args.certs_dir)
|
|
63
|
+
if args.command == "export-indicators":
|
|
64
|
+
return run_export(
|
|
65
|
+
csv_path=args.csv or indicators_csv_path(),
|
|
66
|
+
fmt=args.format,
|
|
67
|
+
ndjson=args.ndjson,
|
|
68
|
+
verify=args.verify,
|
|
69
|
+
certs_dir=args.certs_dir,
|
|
70
|
+
output_dir=args.output_dir,
|
|
71
|
+
check_committed_rules=args.check_committed_rules,
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
parser.error(f"unknown command: {args.command}")
|
|
75
|
+
return 2
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
if __name__ == "__main__":
|
|
79
|
+
raise SystemExit(main())
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
-----BEGIN CERTIFICATE-----
|
|
2
|
+
MIIDaDCCAu6gAwIBAgIQAKSu5njyM2K0wORgt3LyFDAKBggqhkjOPQQDAzBWMQsw
|
|
3
|
+
CQYDVQQGEwJJTjElMCMGA1UECgwcZU11ZGhyYSBUZWNobm9sb2dpZXMgTGltaXRl
|
|
4
|
+
ZDEgMB4GA1UEAwwXZW1TaWduIFJvb3QgVExTIENBIC0gRzMwHhcNMjUwNDMwMTU1
|
|
5
|
+
NDA4WhcNNDAwNDI4MTgzMDAwWjA/MQswCQYDVQQGEwJOTDETMBEGA1UECgwKZU11
|
|
6
|
+
ZGhyYSBCVjEbMBkGA1UEAwwSRU0gRFYgVExTIENBIC0gRzNCMHYwEAYHKoZIzj0C
|
|
7
|
+
AQYFK4EEACIDYgAE557ZwEqXc8RzXlERHahawr1eZKs3S4DhLLwgOOweTw47gS/J
|
|
8
|
+
hZ4eZ6+wTi+LyX90hbplqpEe6KTkW2LVzAPVa+Z4s8OMtNyTfKJGDiOEU8iSk10p
|
|
9
|
+
1E+R4VYGtjzO2rRoo4IBljCCAZIwHwYDVR0jBBgwFoAU4TqrIXzx401UrtRyt/2L
|
|
10
|
+
WUIgkFQwHQYDVR0OBBYEFOIeL+ccGTkOVUtiwSAkVzUkiiUUMB0GA1UdJQQWMBQG
|
|
11
|
+
CCsGAQUFBwMBBggrBgEFBQcDAjBdBgNVHSAEVjBUMDkGCysGAQQBg44hAQABMCow
|
|
12
|
+
KAYIKwYBBQUHAgEWHGh0dHA6Ly9yZXBvc2l0b3J5LmVtc2lnbi5jb20wDQYLKwYB
|
|
13
|
+
BAGDjiEBAmQwCAYGZ4EMAQIBMHUGCCsGAQUFBwEBBGkwZzAkBggrBgEFBQcwAYYY
|
|
14
|
+
aHR0cDovL29jc3AtYi5lbXNpZ24uY29tMD8GCCsGAQUFBzAChjNodHRwOi8vcmVw
|
|
15
|
+
b3NpdG9yeS5lbXNpZ24uY29tL2NlcnRzL0VNRFZUTFNDQUczQi5wN2MwNwYDVR0f
|
|
16
|
+
BDAwLjAsoCqgKIYmaHR0cDovL2NybC5lbXNpZ24uY29tLz9yb290dGxzY2FnMy5j
|
|
17
|
+
cmwwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQAwCgYIKoZIzj0E
|
|
18
|
+
AwMDaAAwZQIwLmsGXi6oFMJ2klkcEMXMug6gvxQWZWkewiDWVzQyl2L6z6DuQfPO
|
|
19
|
+
Ibh1grvdULDCAjEAxZvLlxUavG69J6wnSjC8XBbqNIQsJ6CE2QdNOe84Ptxb6VG8
|
|
20
|
+
gt2TlfJbHii+KNvK
|
|
21
|
+
-----END CERTIFICATE-----
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
-----BEGIN CERTIFICATE-----
|
|
2
|
+
MIIDaDCCAu6gAwIBAgIPWIsuPCu4zaE+GhIJJUMhMAoGCCqGSM49BAMDMFYxCzAJ
|
|
3
|
+
BgNVBAYTAklOMSUwIwYDVQQKDBxlTXVkaHJhIFRlY2hub2xvZ2llcyBMaW1pdGVk
|
|
4
|
+
MSAwHgYDVQQDDBdlbVNpZ24gUm9vdCBUTFMgQ0EgLSBHMzAeFw0yNTA0MzAxNTM1
|
|
5
|
+
MDlaFw00MDA0MjgxODMwMDBaMEAxCzAJBgNVBAYTAlVTMRQwEgYDVQQKDAtlTXVk
|
|
6
|
+
aHJhIEluYzEbMBkGA1UEAwwSRU0gRFYgVExTIENBIC0gRzNDMHYwEAYHKoZIzj0C
|
|
7
|
+
AQYFK4EEACIDYgAEOnp4YsjETTJN3WkDOmeCwO/u/kBV5ooSP6A3G6O9kZRRTuFy
|
|
8
|
+
pDPjYw8CvRiAN9nlFJ+bd9uUooHfmHsv6oiLdL3+j9pMEJnubKGVZv4+8OX2sJpV
|
|
9
|
+
bMyLpQVh3xsqRB0Bo4IBljCCAZIwHwYDVR0jBBgwFoAU4TqrIXzx401UrtRyt/2L
|
|
10
|
+
WUIgkFQwHQYDVR0OBBYEFK5+EFw8KZbBqEcnBVnx4D3U5QrzMB0GA1UdJQQWMBQG
|
|
11
|
+
CCsGAQUFBwMBBggrBgEFBQcDAjBdBgNVHSAEVjBUMDkGCysGAQQBg44hAQABMCow
|
|
12
|
+
KAYIKwYBBQUHAgEWHGh0dHA6Ly9yZXBvc2l0b3J5LmVtc2lnbi5jb20wDQYLKwYB
|
|
13
|
+
BAGDjiEBAmQwCAYGZ4EMAQIBMHUGCCsGAQUFBwEBBGkwZzAkBggrBgEFBQcwAYYY
|
|
14
|
+
aHR0cDovL29jc3AtYy5lbXNpZ24uY29tMD8GCCsGAQUFBzAChjNodHRwOi8vcmVw
|
|
15
|
+
b3NpdG9yeS5lbXNpZ24uY29tL2NlcnRzL0VNRFZUTFNDQUczQy5wN2MwNwYDVR0f
|
|
16
|
+
BDAwLjAsoCqgKIYmaHR0cDovL2NybC5lbXNpZ24uY29tLz9yb290dGxzY2FnMy5j
|
|
17
|
+
cmwwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQAwCgYIKoZIzj0E
|
|
18
|
+
AwMDaAAwZQIxAMEN2HWMocbuWdy1d33pH6JpMvP/V/DIS5PtZbv1Q7TXEbxrcyxg
|
|
19
|
+
yuddOJscYDJJlAIwB4sH1BpbScDzkdD4tJBSwrG/1Mx82vb8YaySehNuu1+1oXNd
|
|
20
|
+
AEKwaJ0mVzScy2+6
|
|
21
|
+
-----END CERTIFICATE-----
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
-----BEGIN CERTIFICATE-----
|
|
2
|
+
MIIDaDCCAu2gAwIBAgIQAMfEHv6S2CXwXq6EGkqCwTAKBggqhkjOPQQDAzBWMQsw
|
|
3
|
+
CQYDVQQGEwJJTjElMCMGA1UECgwcZU11ZGhyYSBUZWNobm9sb2dpZXMgTGltaXRl
|
|
4
|
+
ZDEgMB4GA1UEAwwXZW1TaWduIFJvb3QgVExTIENBIC0gRzMwHhcNMjUwNDMwMTYw
|
|
5
|
+
MzMxWhcNNDAwNDI4MTgzMDAwWjA/MQswCQYDVQQGEwJOTDETMBEGA1UECgwKZU11
|
|
6
|
+
ZGhyYSBCVjEbMBkGA1UEAwwSRU0gRVYgVExTIENBIC0gRzNCMHYwEAYHKoZIzj0C
|
|
7
|
+
AQYFK4EEACIDYgAEJduoWmTTl9oLEFLp6lRuSHvv6pydnWigxerc/u91ppu11vwB
|
|
8
|
+
9Cv7ym60C81kwHZ+Nv/QXZeoE8WqDGyVMOec9fCGZGjxOAZCCqXIUYQLHiUlQOeQ
|
|
9
|
+
5LZUw4Uu1krx6GV9o4IBlTCCAZEwHwYDVR0jBBgwFoAU4TqrIXzx401UrtRyt/2L
|
|
10
|
+
WUIgkFQwHQYDVR0OBBYEFD7cINmJRpiHe4c/2IFHslwV2EcGMB0GA1UdJQQWMBQG
|
|
11
|
+
CCsGAQUFBwMBBggrBgEFBQcDAjBcBgNVHSAEVTBTMDkGCysGAQQBg44hAQABMCow
|
|
12
|
+
KAYIKwYBBQUHAgEWHGh0dHA6Ly9yZXBvc2l0b3J5LmVtc2lnbi5jb20wDQYLKwYB
|
|
13
|
+
BAGDjiEBAngwBwYFZ4EMAQEwdQYIKwYBBQUHAQEEaTBnMCQGCCsGAQUFBzABhhho
|
|
14
|
+
dHRwOi8vb2NzcC1iLmVtc2lnbi5jb20wPwYIKwYBBQUHMAKGM2h0dHA6Ly9yZXBv
|
|
15
|
+
c2l0b3J5LmVtc2lnbi5jb20vY2VydHMvRU1FVlRMU0NBRzNCLnA3YzA3BgNVHR8E
|
|
16
|
+
MDAuMCygKqAohiZodHRwOi8vY3JsLmVtc2lnbi5jb20vP3Jvb3R0bHNjYWczLmNy
|
|
17
|
+
bDAOBgNVHQ8BAf8EBAMCAQYwEgYDVR0TAQH/BAgwBgEB/wIBADAKBggqhkjOPQQD
|
|
18
|
+
AwNpADBmAjEA9Jq999oaOUKhFwopw33iCmt0OHIn3gjT43GfuOHR/YckXdwoNdDA
|
|
19
|
+
lIEhz0NgRO3/AjEAvY/a3OMvktIZLYjn+WLKmp0QhrIMV+e6EpS7j4GVeOKouNp6
|
|
20
|
+
MN/P+ByGeiRMghzB
|
|
21
|
+
-----END CERTIFICATE-----
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
-----BEGIN CERTIFICATE-----
|
|
2
|
+
MIIDaDCCAu6gAwIBAgIQAIAJkopkEHYBrwX6LxnxCTAKBggqhkjOPQQDAzBWMQsw
|
|
3
|
+
CQYDVQQGEwJJTjElMCMGA1UECgwcZU11ZGhyYSBUZWNobm9sb2dpZXMgTGltaXRl
|
|
4
|
+
ZDEgMB4GA1UEAwwXZW1TaWduIFJvb3QgVExTIENBIC0gRzMwHhcNMjUwNDMwMTUz
|
|
5
|
+
OTMxWhcNNDAwNDI4MTgzMDAwWjBAMQswCQYDVQQGEwJVUzEUMBIGA1UECgwLZU11
|
|
6
|
+
ZGhyYSBJbmMxGzAZBgNVBAMMEkVNIEVWIFRMUyBDQSAtIEczQzB2MBAGByqGSM49
|
|
7
|
+
AgEGBSuBBAAiA2IABC1W6Cmm+4LGSkaX2WCvlR6QZ66R+SbTQwbaSKiq63hptqZ+
|
|
8
|
+
bSdCbgRCqgOzbhmI3/Y2UU7hzwf1uks/8qBmRa59MdWGatMao9JG6wsxd+6Zy3Vm
|
|
9
|
+
xRbOdICKZo+R8MR/yqOCAZUwggGRMB8GA1UdIwQYMBaAFOE6qyF88eNNVK7Ucrf9
|
|
10
|
+
i1lCIJBUMB0GA1UdDgQWBBSmJV6AqU2385Z8G8eR35K87kvrXzAdBgNVHSUEFjAU
|
|
11
|
+
BggrBgEFBQcDAQYIKwYBBQUHAwIwXAYDVR0gBFUwUzA5BgsrBgEEAYOOIQEAATAq
|
|
12
|
+
MCgGCCsGAQUFBwIBFhxodHRwOi8vcmVwb3NpdG9yeS5lbXNpZ24uY29tMA0GCysG
|
|
13
|
+
AQQBg44hAQJ4MAcGBWeBDAEBMHUGCCsGAQUFBwEBBGkwZzAkBggrBgEFBQcwAYYY
|
|
14
|
+
aHR0cDovL29jc3AtYy5lbXNpZ24uY29tMD8GCCsGAQUFBzAChjNodHRwOi8vcmVw
|
|
15
|
+
b3NpdG9yeS5lbXNpZ24uY29tL2NlcnRzL0VNRVZUTFNDQUczQy5wN2MwNwYDVR0f
|
|
16
|
+
BDAwLjAsoCqgKIYmaHR0cDovL2NybC5lbXNpZ24uY29tLz9yb290dGxzY2FnMy5j
|
|
17
|
+
cmwwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQAwCgYIKoZIzj0E
|
|
18
|
+
AwMDaAAwZQIwBy1wTnzH4lXDTy2PD91ysLjvnlVN3JbJmc1BIMEU8TOLkYVHibMc
|
|
19
|
+
9HeyonikFSfmAjEA6uE3QRxlrZTz/1/lXPTEMUhoauAtycagtlNFp79kjhvNa2/f
|
|
20
|
+
Aal1GNxsOutLnr0Y
|
|
21
|
+
-----END CERTIFICATE-----
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
-----BEGIN CERTIFICATE-----
|
|
2
|
+
MIIDWzCCAuCgAwIBAgIPeBiTP4+FtGGaKzX7qD0KMAoGCCqGSM49BAMDMFUxCzAJ
|
|
3
|
+
BgNVBAYTAklOMSUwIwYDVQQKDBxlTXVkaHJhIFRlY2hub2xvZ2llcyBMaW1pdGVk
|
|
4
|
+
MR8wHQYDVQQDDBZlbVNpZ24gUm9vdCBDUyBDQSAtIEczMB4XDTI1MDQzMDE2MDgy
|
|
5
|
+
N1oXDTQwMDQyODE4MzAwMFowPjELMAkGA1UEBhMCTkwxEzARBgNVBAoMCmVNdWRo
|
|
6
|
+
cmEgQlYxGjAYBgNVBAMMEUVNIE9WIENTIENBIC0gRzNCMHYwEAYHKoZIzj0CAQYF
|
|
7
|
+
K4EEACIDYgAEqrsPsGZqz88B+tUr/P1MK/LLPDSX3nOVDlgZth/mlQmHQcjEkUOb
|
|
8
|
+
NKBDHK/+W/m0wcjorgAB+fTcitgsWfNjnpbNbD1NsM7+wmw9YlF7N3YTcnQ/jord
|
|
9
|
+
d7EAZPKr5eBQo4IBizCCAYcwHwYDVR0jBBgwFoAUaHQD+IXKjVRQVx0W4MjeRQ2r
|
|
10
|
+
zS0wHQYDVR0OBBYEFHn66OzP2w11jaRY1p+27dx8Sd7mMBMGA1UdJQQMMAoGCCsG
|
|
11
|
+
AQUFBwMDMF4GA1UdIARXMFUwOQYLKwYBBAGDjiEBAAEwKjAoBggrBgEFBQcCARYc
|
|
12
|
+
aHR0cDovL3JlcG9zaXRvcnkuZW1zaWduLmNvbTAOBgwrBgEEAYOOIQECgUgwCAYG
|
|
13
|
+
Z4EMAQQBMHQGCCsGAQUFBwEBBGgwZjAkBggrBgEFBQcwAYYYaHR0cDovL29jc3At
|
|
14
|
+
Yi5lbXNpZ24uY29tMD4GCCsGAQUFBzAChjJodHRwOi8vcmVwb3NpdG9yeS5lbXNp
|
|
15
|
+
Z24uY29tL2NlcnRzL0VNT1ZDU0NBRzNCLnA3YzA2BgNVHR8ELzAtMCugKaAnhiVo
|
|
16
|
+
dHRwOi8vY3JsLmVtc2lnbi5jb20vP3Jvb3Rjc2NhZzMuY3JsMA4GA1UdDwEB/wQE
|
|
17
|
+
AwIBBjASBgNVHRMBAf8ECDAGAQH/AgEAMAoGCCqGSM49BAMDA2kAMGYCMQC/zr03
|
|
18
|
+
YEELsNKqzUtH2dVFi4BaKFdyrr/6G1dIWp8KAVgsw2/u4lyyboUDaC9jDvICMQC9
|
|
19
|
+
HTxku84tNX9dmHOtH7aC2Nu/JM0jTf6KjZAvovCJzzv1IFWSZpVLZibynMLXOrM=
|
|
20
|
+
-----END CERTIFICATE-----
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
-----BEGIN CERTIFICATE-----
|
|
2
|
+
MIIDWzCCAuGgAwIBAgIPVEt/kiwxriIKSpIpFvbmMAoGCCqGSM49BAMDMFUxCzAJ
|
|
3
|
+
BgNVBAYTAklOMSUwIwYDVQQKDBxlTXVkaHJhIFRlY2hub2xvZ2llcyBMaW1pdGVk
|
|
4
|
+
MR8wHQYDVQQDDBZlbVNpZ24gUm9vdCBDUyBDQSAtIEczMB4XDTI1MDQzMDE2Mzg0
|
|
5
|
+
MFoXDTQwMDQyODE4MzAwMFowPzELMAkGA1UEBhMCVVMxFDASBgNVBAoMC2VNdWRo
|
|
6
|
+
cmEgSW5jMRowGAYDVQQDDBFFTSBPViBDUyBDQSAtIEczQzB2MBAGByqGSM49AgEG
|
|
7
|
+
BSuBBAAiA2IABLnw4GNHAqacpqrdRDz9YsQbm6SyCSRpfXl052kaEm+5avs+NML9
|
|
8
|
+
O8X0gwYfJl3CpYQ2NHMjUQQ2so8E84YjYwZ5gOJQPgJTLWVGI1pxZaJZoe9Jb3Qb
|
|
9
|
+
X97neHII5Lj676OCAYswggGHMB8GA1UdIwQYMBaAFGh0A/iFyo1UUFcdFuDI3kUN
|
|
10
|
+
q80tMB0GA1UdDgQWBBTub3MpjW+/p7Mbw5U09hVWRHhmtzATBgNVHSUEDDAKBggr
|
|
11
|
+
BgEFBQcDAzBeBgNVHSAEVzBVMDkGCysGAQQBg44hAQABMCowKAYIKwYBBQUHAgEW
|
|
12
|
+
HGh0dHA6Ly9yZXBvc2l0b3J5LmVtc2lnbi5jb20wDgYMKwYBBAGDjiEBAoFIMAgG
|
|
13
|
+
BmeBDAEEATB0BggrBgEFBQcBAQRoMGYwJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3Nw
|
|
14
|
+
LWMuZW1zaWduLmNvbTA+BggrBgEFBQcwAoYyaHR0cDovL3JlcG9zaXRvcnkuZW1z
|
|
15
|
+
aWduLmNvbS9jZXJ0cy9FTU9WQ1NDQUczQy5wN2MwNgYDVR0fBC8wLTAroCmgJ4Yl
|
|
16
|
+
aHR0cDovL2NybC5lbXNpZ24uY29tLz9yb290Y3NjYWczLmNybDAOBgNVHQ8BAf8E
|
|
17
|
+
BAMCAQYwEgYDVR0TAQH/BAgwBgEB/wIBADAKBggqhkjOPQQDAwNoADBlAjEA8yPg
|
|
18
|
+
8sntOhLwV2QXJ5LEaKSpo/fnE3uOgTadK73fDhyjiqr0Io9GVuQTYqBPbQ2TAjBg
|
|
19
|
+
euApmBS486+iei03lRrp139dPw6k28jjGNvWsAU7A1N86J1zPJVDEyVH+nMAWC0=
|
|
20
|
+
-----END CERTIFICATE-----
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
-----BEGIN CERTIFICATE-----
|
|
2
|
+
MIIDZjCCAu2gAwIBAgIPbK2jZ/scEACIEg6iAtVoMAoGCCqGSM49BAMDMFYxCzAJ
|
|
3
|
+
BgNVBAYTAklOMSUwIwYDVQQKDBxlTXVkaHJhIFRlY2hub2xvZ2llcyBMaW1pdGVk
|
|
4
|
+
MSAwHgYDVQQDDBdlbVNpZ24gUm9vdCBUTFMgQ0EgLSBHMzAeFw0yNTA0MzAxNjAw
|
|
5
|
+
MTJaFw00MDA0MjgxODMwMDBaMD8xCzAJBgNVBAYTAk5MMRMwEQYDVQQKDAplTXVk
|
|
6
|
+
aHJhIEJWMRswGQYDVQQDDBJFTSBPViBUTFMgQ0EgLSBHM0IwdjAQBgcqhkjOPQIB
|
|
7
|
+
BgUrgQQAIgNiAARziXqg6zz9yosSQC/68KvE4SErr43ud4rJ7i1tuD+sKAxeBWOK
|
|
8
|
+
56Ks1xwyKo42HN659pxDArndjXPRzGyqsswK7k4hbOl53VGKSvS2JuVoTN1lgDft
|
|
9
|
+
DIVOTMEvTPhkbQ2jggGWMIIBkjAfBgNVHSMEGDAWgBThOqshfPHjTVSu1HK3/YtZ
|
|
10
|
+
QiCQVDAdBgNVHQ4EFgQUm9hlUa/n5yw3rQjuaRnZvzeErgowHQYDVR0lBBYwFAYI
|
|
11
|
+
KwYBBQUHAwEGCCsGAQUFBwMCMF0GA1UdIARWMFQwOQYLKwYBBAGDjiEBAAEwKjAo
|
|
12
|
+
BggrBgEFBQcCARYcaHR0cDovL3JlcG9zaXRvcnkuZW1zaWduLmNvbTANBgsrBgEE
|
|
13
|
+
AYOOIQECbjAIBgZngQwBAgIwdQYIKwYBBQUHAQEEaTBnMCQGCCsGAQUFBzABhhho
|
|
14
|
+
dHRwOi8vb2NzcC1iLmVtc2lnbi5jb20wPwYIKwYBBQUHMAKGM2h0dHA6Ly9yZXBv
|
|
15
|
+
c2l0b3J5LmVtc2lnbi5jb20vY2VydHMvRU1PVlRMU0NBRzNCLnA3YzA3BgNVHR8E
|
|
16
|
+
MDAuMCygKqAohiZodHRwOi8vY3JsLmVtc2lnbi5jb20vP3Jvb3R0bHNjYWczLmNy
|
|
17
|
+
bDAOBgNVHQ8BAf8EBAMCAQYwEgYDVR0TAQH/BAgwBgEB/wIBADAKBggqhkjOPQQD
|
|
18
|
+
AwNnADBkAjBAk+5BizdJhrED3wb7F2Gm7bWI60dlNd075nghT2TrR4NWKZtJZcbc
|
|
19
|
+
28xxIY/NONICMF6mPdsjosaqmvEMWqKcBh4vsIvXSKnQj5o8zrFB4oKS+accjYTe
|
|
20
|
+
8Dz3bQjauvy9uw==
|
|
21
|
+
-----END CERTIFICATE-----
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
-----BEGIN CERTIFICATE-----
|
|
2
|
+
MIIDaDCCAu6gAwIBAgIPKWkmwiejoVJjkrGUgqUEMAoGCCqGSM49BAMDMFYxCzAJ
|
|
3
|
+
BgNVBAYTAklOMSUwIwYDVQQKDBxlTXVkaHJhIFRlY2hub2xvZ2llcyBMaW1pdGVk
|
|
4
|
+
MSAwHgYDVQQDDBdlbVNpZ24gUm9vdCBUTFMgQ0EgLSBHMzAeFw0yNTA0MzAxNTM3
|
|
5
|
+
NDFaFw00MDA0MjgxODMwMDBaMEAxCzAJBgNVBAYTAlVTMRQwEgYDVQQKDAtlTXVk
|
|
6
|
+
aHJhIEluYzEbMBkGA1UEAwwSRU0gT1YgVExTIENBIC0gRzNDMHYwEAYHKoZIzj0C
|
|
7
|
+
AQYFK4EEACIDYgAEE4JRzVKskpjByKrZdzId65fnCb0LTKCspV3IrVHc/J0ViaFZ
|
|
8
|
+
fjpRIOHv1jHGPhg1ysrimGmmLhYx6KKBgatWYW3EXZGKvAnzqw5jz3kqpNztc4e+
|
|
9
|
+
N7ulaVSfHAKycO1no4IBljCCAZIwHwYDVR0jBBgwFoAU4TqrIXzx401UrtRyt/2L
|
|
10
|
+
WUIgkFQwHQYDVR0OBBYEFDTq6gzryQra+dDF4u2beMmHnhtsMB0GA1UdJQQWMBQG
|
|
11
|
+
CCsGAQUFBwMBBggrBgEFBQcDAjBdBgNVHSAEVjBUMDkGCysGAQQBg44hAQABMCow
|
|
12
|
+
KAYIKwYBBQUHAgEWHGh0dHA6Ly9yZXBvc2l0b3J5LmVtc2lnbi5jb20wDQYLKwYB
|
|
13
|
+
BAGDjiEBAm4wCAYGZ4EMAQICMHUGCCsGAQUFBwEBBGkwZzAkBggrBgEFBQcwAYYY
|
|
14
|
+
aHR0cDovL29jc3AtYy5lbXNpZ24uY29tMD8GCCsGAQUFBzAChjNodHRwOi8vcmVw
|
|
15
|
+
b3NpdG9yeS5lbXNpZ24uY29tL2NlcnRzL0VNT1ZUTFNDQUczQy5wN2MwNwYDVR0f
|
|
16
|
+
BDAwLjAsoCqgKIYmaHR0cDovL2NybC5lbXNpZ24uY29tLz9yb290dGxzY2FnMy5j
|
|
17
|
+
cmwwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQAwCgYIKoZIzj0E
|
|
18
|
+
AwMDaAAwZQIxAMSZt2xsPeumRdeSMSQ3CbzIZeQ/q7GDCWfeE1Pq+mhgA6gRM44c
|
|
19
|
+
NVF3xJ+wsxJk+wIwFJbaDMokD8Ei6eNOiA8yUMYvfzQyngmrhZQMdPCK1SewrR79
|
|
20
|
+
4rSb9vGqxZzelQth
|
|
21
|
+
-----END CERTIFICATE-----
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
ca_common_name,type,sha256_fingerprint,serial,issuer,pem_basename,suricata_sid,tls_issuer_cn_match,bug_id
|
|
2
|
+
EM DV TLS CA - G3B,TLS,42c4accd12c4f59597925e1a08a7a90102608543809308d50ec427e118ba1493,A4AEE678F23362B4C0E460B772F214,emSign Root TLS CA - G3,EMDVTLSCAG3B,92083401,EM DV TLS CA - G3B,2083449
|
|
3
|
+
EM DV TLS CA - G3C,TLS,0164d7ceae5bb909c272af151ff44b1177ae9b47d9424b94f1d9558c30934d19,588B2E3C2BB8CDA13E1A1209254321,emSign Root TLS CA - G3,EMDVTLSCAG3C,92083402,EM DV TLS CA - G3C,2083449
|
|
4
|
+
EM EV TLS CA - G3B,TLS,e7568fe6e12331f4fd7de61da4c7559d0f8eb192a218d4741a3ba75184333838,C7C41EFE92D825F05EAE841A4A82C1,emSign Root TLS CA - G3,EMEVTLSCAG3B,92083403,EM EV TLS CA - G3B,2083449
|
|
5
|
+
EM EV TLS CA - G3C,TLS,432ec25f0d28de9006d97bf752f17bbb2cd41f669933fcb072d9a1148d0261f3,8009928A64107601AF05FA2F19F109,emSign Root TLS CA - G3,EMEVTLSCAG3C,92083404,EM EV TLS CA - G3C,2083449
|
|
6
|
+
EM OV TLS CA - G3B,TLS,98b896625c0c230adeec3eb2cf6aad5001ecf9156a68644e82374ce5833bc25b,6CADA367FB1C100088120EA202D568,emSign Root TLS CA - G3,EMOVTLSCAG3B,92083405,EM OV TLS CA - G3B,2083449
|
|
7
|
+
EM OV TLS CA - G3C,TLS,cb6e15165ac802e9b3f993f16c25d41f4e81c21ebde71ae1b012ac00bf9c7c3f,296926C227A3A1526392B19482A504,emSign Root TLS CA - G3,EMOVTLSCAG3C,92083406,EM OV TLS CA - G3C,2083449
|
|
8
|
+
EM OV CS CA - G3B,CodeSigning,9e39de2881273acc225a149c72ba3e0f51424963669ab633ee1dc7df5db067b4,7818933F8F85B4619A2B35FBA83D0A,emSign Root CS CA - G3,EMOVCSCAG3B,92083407,EM OV CS CA - G3B,2083449
|
|
9
|
+
EM OV CS CA - G3C,CodeSigning,4b2460a466f95fd40113bcdcca2ceb29b3b093921de45474da7df48874c630b1,544B7F922C31AE220A4A922916F6E6,emSign Root CS CA - G3,EMOVCSCAG3C,92083408,EM OV CS CA - G3C,2083449
|
|
10
|
+
emSign Root TLS CA - G3,RootTLS,7dd78d5f4f13459a83dff9abbba62edbaf6f2d102bf257fd712f4d9f2746ed8d,,,,,,2083449
|
|
11
|
+
emSign Root CS CA - G3,RootCS,f2edaaff3d9b701fb4d14c9f285f8c0bad90fc3bcc1fa07d47f4718edaba34a5,,,,,,2083449
|
|
12
|
+
AAA Certificate Services,CrossSign,d7a7a0fb5d7e2731d771e9484ebcdef71d5f0c3e0a2948782bc83ee0ea699ef4,,,,,,2083449
|
emsign_g3/distrust.py
ADDED
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
"""Explicitly distrust the eight compromised eMudhra/emSign G3 intermediates."""
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
import glob
|
|
5
|
+
import hashlib
|
|
6
|
+
import os
|
|
7
|
+
import platform
|
|
8
|
+
import subprocess
|
|
9
|
+
import sys
|
|
10
|
+
from pathlib import Path
|
|
11
|
+
|
|
12
|
+
from emsign_g3.indicators import expected_pem_fingerprints
|
|
13
|
+
from emsign_g3.paths import default_certs_dir
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def sha256_of_pem(path: str | Path) -> str | None:
|
|
17
|
+
der = subprocess.run(
|
|
18
|
+
["openssl", "x509", "-inform", "PEM", "-outform", "DER", "-in", str(path)],
|
|
19
|
+
capture_output=True,
|
|
20
|
+
).stdout
|
|
21
|
+
return hashlib.sha256(der).hexdigest() if der else None
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def load_certs(certs_dir: str | Path) -> list[tuple[str, str, str]]:
|
|
25
|
+
certs: list[tuple[str, str, str]] = []
|
|
26
|
+
expected = expected_pem_fingerprints()
|
|
27
|
+
for path in sorted(glob.glob(os.path.join(str(certs_dir), "EM*.pem"))):
|
|
28
|
+
name = os.path.splitext(os.path.basename(path))[0]
|
|
29
|
+
fp = sha256_of_pem(path)
|
|
30
|
+
want = expected.get(name)
|
|
31
|
+
if want and fp == want:
|
|
32
|
+
certs.append((name, path, fp))
|
|
33
|
+
else:
|
|
34
|
+
print(f" !! skip {name}: fingerprint mismatch or unknown ({fp})", file=sys.stderr)
|
|
35
|
+
return certs
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def plan_for_os(system: str, certs: list[tuple[str, str, str]], undo: bool):
|
|
39
|
+
steps: list[tuple[str, list[str], str]] = []
|
|
40
|
+
if system == "Darwin":
|
|
41
|
+
kc = "/Library/Keychains/System.keychain"
|
|
42
|
+
for name, path, _ in certs:
|
|
43
|
+
if undo:
|
|
44
|
+
steps.append(
|
|
45
|
+
(
|
|
46
|
+
f"macOS: remove distrust for {name}",
|
|
47
|
+
["sudo", "security", "remove-trusted-cert", "-d", path],
|
|
48
|
+
"re-run without --undo to re-apply",
|
|
49
|
+
)
|
|
50
|
+
)
|
|
51
|
+
else:
|
|
52
|
+
steps.append(
|
|
53
|
+
(
|
|
54
|
+
f"macOS: distrust {name} (admin System keychain)",
|
|
55
|
+
[
|
|
56
|
+
"sudo",
|
|
57
|
+
"security",
|
|
58
|
+
"add-trusted-cert",
|
|
59
|
+
"-d",
|
|
60
|
+
"-r",
|
|
61
|
+
"deny",
|
|
62
|
+
"-k",
|
|
63
|
+
kc,
|
|
64
|
+
path,
|
|
65
|
+
],
|
|
66
|
+
f"sudo security remove-trusted-cert -d {path}",
|
|
67
|
+
)
|
|
68
|
+
)
|
|
69
|
+
elif system == "Linux":
|
|
70
|
+
blk = (
|
|
71
|
+
"/etc/pki/ca-trust/source/blocklist"
|
|
72
|
+
if os.path.isdir("/etc/pki/ca-trust")
|
|
73
|
+
else "/usr/local/share/ca-certificates/emsign-blocklist"
|
|
74
|
+
)
|
|
75
|
+
update = (
|
|
76
|
+
["sudo", "update-ca-trust"]
|
|
77
|
+
if os.path.isdir("/etc/pki/ca-trust")
|
|
78
|
+
else ["sudo", "update-ca-certificates"]
|
|
79
|
+
)
|
|
80
|
+
for name, path, _ in certs:
|
|
81
|
+
dst = os.path.join(blk, f"{name}.pem")
|
|
82
|
+
if undo:
|
|
83
|
+
steps.append(
|
|
84
|
+
(
|
|
85
|
+
f"Linux: unblock {name}",
|
|
86
|
+
["sudo", "rm", "-f", dst],
|
|
87
|
+
"restore by re-running without --undo",
|
|
88
|
+
)
|
|
89
|
+
)
|
|
90
|
+
else:
|
|
91
|
+
steps.append(
|
|
92
|
+
(
|
|
93
|
+
f"Linux: blocklist {name} -> {dst}",
|
|
94
|
+
["sudo", "install", "-D", "-m", "644", path, dst],
|
|
95
|
+
f"sudo rm -f {dst} && {' '.join(update)}",
|
|
96
|
+
)
|
|
97
|
+
)
|
|
98
|
+
steps.append(("Linux: refresh trust store", update, "(same command re-runs)"))
|
|
99
|
+
elif system == "Windows":
|
|
100
|
+
for name, path, _ in certs:
|
|
101
|
+
if undo:
|
|
102
|
+
steps.append(
|
|
103
|
+
(
|
|
104
|
+
f"Windows: remove {name} from disallowed",
|
|
105
|
+
["certutil", "-delstore", "disallowed", path],
|
|
106
|
+
"re-add with certutil -addstore -f disallowed",
|
|
107
|
+
)
|
|
108
|
+
)
|
|
109
|
+
else:
|
|
110
|
+
steps.append(
|
|
111
|
+
(
|
|
112
|
+
f"Windows: add {name} to disallowed store",
|
|
113
|
+
["certutil", "-addstore", "-f", "disallowed", path],
|
|
114
|
+
f"certutil -delstore disallowed <serial-of-{name}>",
|
|
115
|
+
)
|
|
116
|
+
)
|
|
117
|
+
home = os.path.expanduser("~")
|
|
118
|
+
for base in (
|
|
119
|
+
os.path.join(home, ".mozilla", "firefox"),
|
|
120
|
+
os.path.join(home, "Library", "Application Support", "Firefox", "Profiles"),
|
|
121
|
+
os.path.join(os.environ.get("APPDATA", ""), "Mozilla", "Firefox", "Profiles"),
|
|
122
|
+
):
|
|
123
|
+
if base and os.path.isdir(base):
|
|
124
|
+
for d in os.listdir(base):
|
|
125
|
+
prof = os.path.join(base, d)
|
|
126
|
+
if os.path.exists(os.path.join(prof, "cert9.db")):
|
|
127
|
+
for name, path, _ in certs:
|
|
128
|
+
if undo:
|
|
129
|
+
steps.append(
|
|
130
|
+
(
|
|
131
|
+
f"NSS {d}: delete distrust entry {name}",
|
|
132
|
+
[
|
|
133
|
+
"certutil",
|
|
134
|
+
"-D",
|
|
135
|
+
"-n",
|
|
136
|
+
f"emSign-distrust-{name}",
|
|
137
|
+
"-d",
|
|
138
|
+
"sql:" + prof,
|
|
139
|
+
],
|
|
140
|
+
"re-run without --undo",
|
|
141
|
+
)
|
|
142
|
+
)
|
|
143
|
+
else:
|
|
144
|
+
steps.append(
|
|
145
|
+
(
|
|
146
|
+
f"NSS {d}: mark {name} explicitly distrusted (p,p,p)",
|
|
147
|
+
[
|
|
148
|
+
"certutil",
|
|
149
|
+
"-A",
|
|
150
|
+
"-n",
|
|
151
|
+
f"emSign-distrust-{name}",
|
|
152
|
+
"-t",
|
|
153
|
+
"p,p,p",
|
|
154
|
+
"-d",
|
|
155
|
+
"sql:" + prof,
|
|
156
|
+
"-i",
|
|
157
|
+
path,
|
|
158
|
+
],
|
|
159
|
+
f"certutil -D -n emSign-distrust-{name} -d sql:{prof}",
|
|
160
|
+
)
|
|
161
|
+
)
|
|
162
|
+
return steps
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
def run_distrust(
|
|
166
|
+
*,
|
|
167
|
+
apply: bool = False,
|
|
168
|
+
undo: bool = False,
|
|
169
|
+
certs_dir: str | Path | None = None,
|
|
170
|
+
) -> int:
|
|
171
|
+
certs_path = Path(certs_dir) if certs_dir else default_certs_dir()
|
|
172
|
+
system = platform.system()
|
|
173
|
+
certs = load_certs(certs_path)
|
|
174
|
+
if len(certs) != 8:
|
|
175
|
+
print(
|
|
176
|
+
f"WARNING: expected 8 verified intermediate PEMs, found {len(certs)} in "
|
|
177
|
+
f"{certs_path}. Proceeding with what verified.",
|
|
178
|
+
file=sys.stderr,
|
|
179
|
+
)
|
|
180
|
+
steps = plan_for_os(system, certs, undo)
|
|
181
|
+
|
|
182
|
+
verb = "ROLLBACK" if undo else "DISTRUST"
|
|
183
|
+
print(
|
|
184
|
+
f"# emSign-G3 {verb} plan on {platform.node()} ({system}) — "
|
|
185
|
+
f"{'APPLY' if apply else 'DRY RUN'}\n"
|
|
186
|
+
)
|
|
187
|
+
if not steps:
|
|
188
|
+
print("No supported trust store found to modify on this host.")
|
|
189
|
+
return 0
|
|
190
|
+
for desc, cmd, undo_hint in steps:
|
|
191
|
+
print(f"* {desc}")
|
|
192
|
+
print(f" cmd: {' '.join(cmd)}")
|
|
193
|
+
if not undo:
|
|
194
|
+
print(f" undo: {undo_hint}")
|
|
195
|
+
if apply:
|
|
196
|
+
r = subprocess.run(cmd, capture_output=True, text=True)
|
|
197
|
+
status = "ok" if r.returncode == 0 else f"FAILED rc={r.returncode}"
|
|
198
|
+
print(f" -> {status} {r.stderr.strip()[:160]}")
|
|
199
|
+
print()
|
|
200
|
+
if not apply:
|
|
201
|
+
print("Dry run only. Re-run with --apply (likely under sudo/Administrator) to execute.")
|
|
202
|
+
return 0
|
emsign_g3/elastic.py
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
"""Generate Elastic KQL detection stubs from Bug 2083449 indicators."""
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
import re
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
|
|
7
|
+
from emsign_g3.indicators import COMPROMISED_TYPES, load_rows
|
|
8
|
+
|
|
9
|
+
MOZILLA_BUG = "2083449"
|
|
10
|
+
GENERIC_SID = 92083409
|
|
11
|
+
|
|
12
|
+
_SAFE = re.compile(r"[^a-zA-Z0-9_-]+")
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def _slug(name: str) -> str:
|
|
16
|
+
return _SAFE.sub("_", name).strip("_").lower()
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def build_elastic_kql_rule(row: dict) -> str:
|
|
20
|
+
cn = row["tls_issuer_cn_match"]
|
|
21
|
+
sid = int(row["suricata_sid"])
|
|
22
|
+
serial = row.get("serial") or "unknown"
|
|
23
|
+
lines = [
|
|
24
|
+
f"// eMudhra emSign G3 compromised issuer: {row['ca_common_name']}",
|
|
25
|
+
f"// Mozilla Bug {MOZILLA_BUG} | serial {serial} | Suricata sid {sid}",
|
|
26
|
+
"// Starter KQL for Suricata EVE / ECS-normalized TLS events.",
|
|
27
|
+
"// Adjust field names (e.g. suricata.eve.alert.signature_id) for your stack.",
|
|
28
|
+
f'alert.signature_id == {sid} or tls.issuerdn : *"{cn}"*',
|
|
29
|
+
"",
|
|
30
|
+
]
|
|
31
|
+
return "\n".join(lines)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def build_elastic_kql_backstop() -> str:
|
|
35
|
+
return "\n".join(
|
|
36
|
+
[
|
|
37
|
+
"// eMudhra emSign G3 compromised-family issuer (generic review)",
|
|
38
|
+
f"// Mozilla Bug {MOZILLA_BUG} | Suricata sid {GENERIC_SID}",
|
|
39
|
+
"// Review hits manually; prefer per-CA rules in this directory.",
|
|
40
|
+
f"alert.signature_id == {GENERIC_SID}",
|
|
41
|
+
"",
|
|
42
|
+
]
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def elastic_kql_from_rows(rows: list[dict]) -> list[tuple[str, str]]:
|
|
47
|
+
out: list[tuple[str, str]] = []
|
|
48
|
+
for row in rows:
|
|
49
|
+
if row["type"] not in COMPROMISED_TYPES:
|
|
50
|
+
continue
|
|
51
|
+
base = row.get("pem_basename") or _slug(row["ca_common_name"])
|
|
52
|
+
out.append((f"emsign_g3_{base.lower()}.kql", build_elastic_kql_rule(row)))
|
|
53
|
+
out.append(("emsign_g3_generic_backstop.kql", build_elastic_kql_backstop()))
|
|
54
|
+
return out
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def render_elastic_kql_bundle(rows: list[dict] | None = None) -> str:
|
|
58
|
+
rows = rows if rows is not None else load_rows()
|
|
59
|
+
parts = [content for _, content in elastic_kql_from_rows(rows)]
|
|
60
|
+
return "\n".join(parts)
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def write_elastic_kql_rules(output_dir: Path, rows: list[dict] | None = None) -> list[Path]:
|
|
64
|
+
output_dir.mkdir(parents=True, exist_ok=True)
|
|
65
|
+
written: list[Path] = []
|
|
66
|
+
rows = rows if rows is not None else load_rows()
|
|
67
|
+
for filename, content in elastic_kql_from_rows(rows):
|
|
68
|
+
path = output_dir / filename
|
|
69
|
+
path.write_text(content, encoding="utf-8")
|
|
70
|
+
written.append(path)
|
|
71
|
+
return written
|