reverse-skills-max: initial public release (restored, redacted, hardened)
This commit is contained in:
@@ -0,0 +1,141 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
chipsec-audit — run a CHIPSEC firmware-posture baseline and parse results.
|
||||
|
||||
Wraps the real CHIPSEC CLIs:
|
||||
- chipsec_main : module runner
|
||||
- chipsec_util : SPI/UEFI utilities
|
||||
Project: https://github.com/chipsec/chipsec
|
||||
|
||||
Install:
|
||||
pip install chipsec # needs root and a kernel driver build
|
||||
|
||||
Examples:
|
||||
sudo python agent.py baseline --log chipsec.log --json report.json
|
||||
sudo python agent.py module --name common.bios_wp
|
||||
sudo python agent.py dump --out rom.bin
|
||||
"""
|
||||
import argparse
|
||||
import json
|
||||
import os
|
||||
import re
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
# CHIPSEC prints lines like: [+] PASSED: BIOS region write protection ...
|
||||
RESULT_RE = re.compile(r"\[[+\-!*]\]\s*(PASSED|FAILED|WARNING|ERROR|NOT APPLICABLE|INFORMATION)\b[:\s]*(.*)",
|
||||
re.IGNORECASE)
|
||||
|
||||
CORE_MODULES = [
|
||||
"common.bios_wp",
|
||||
"common.spi_lock",
|
||||
"common.spi_desc",
|
||||
"common.smm",
|
||||
"common.secureboot.variables",
|
||||
]
|
||||
|
||||
|
||||
def _require(tool: str) -> None:
|
||||
if shutil.which(tool) is None:
|
||||
sys.exit(f"error: '{tool}' not found on PATH. Install CHIPSEC: pip install chipsec")
|
||||
|
||||
|
||||
def _warn_root() -> None:
|
||||
if hasattr(os, "geteuid") and os.geteuid() != 0:
|
||||
print("[!] warning: CHIPSEC needs root/Administrator to load its driver.", file=sys.stderr)
|
||||
|
||||
|
||||
def _run(argv: list) -> subprocess.CompletedProcess:
|
||||
print(f"[*] {' '.join(argv)}", file=sys.stderr)
|
||||
return subprocess.run(argv, capture_output=True, text=True)
|
||||
|
||||
|
||||
def parse_results(stdout: str) -> list:
|
||||
findings = []
|
||||
for line in stdout.splitlines():
|
||||
m = RESULT_RE.search(line)
|
||||
if m:
|
||||
findings.append({"result": m.group(1).upper(), "detail": m.group(2).strip()})
|
||||
return findings
|
||||
|
||||
|
||||
def cmd_baseline(args) -> int:
|
||||
_require("chipsec_main")
|
||||
_warn_root()
|
||||
argv = ["chipsec_main"]
|
||||
if args.log:
|
||||
argv += ["-l", args.log]
|
||||
proc = _run(argv)
|
||||
findings = parse_results(proc.stdout)
|
||||
fails = [f for f in findings if f["result"] in ("FAILED", "ERROR")]
|
||||
warns = [f for f in findings if f["result"] == "WARNING"]
|
||||
summary = {
|
||||
"total_results": len(findings),
|
||||
"failed": len(fails),
|
||||
"warnings": len(warns),
|
||||
"failures": fails,
|
||||
"warning_items": warns,
|
||||
}
|
||||
if args.json:
|
||||
with open(args.json, "w", encoding="utf-8") as fh:
|
||||
json.dump({"summary": summary, "all": findings}, fh, indent=2)
|
||||
print(f"[+] report written to {args.json}", file=sys.stderr)
|
||||
print(json.dumps(summary, indent=2))
|
||||
return 1 if fails else 0
|
||||
|
||||
|
||||
def cmd_module(args) -> int:
|
||||
_require("chipsec_main")
|
||||
_warn_root()
|
||||
targets = [args.name] if args.name else CORE_MODULES
|
||||
out = {}
|
||||
rc = 0
|
||||
for mod in targets:
|
||||
proc = _run(["chipsec_main", "-m", mod])
|
||||
res = parse_results(proc.stdout)
|
||||
out[mod] = res
|
||||
if any(r["result"] in ("FAILED", "ERROR") for r in res):
|
||||
rc = 1
|
||||
print(json.dumps(out, indent=2))
|
||||
return rc
|
||||
|
||||
|
||||
def cmd_dump(args) -> int:
|
||||
_require("chipsec_util")
|
||||
_warn_root()
|
||||
_run(["chipsec_util", "spi", "info"])
|
||||
proc = _run(["chipsec_util", "spi", "dump", args.out])
|
||||
if proc.returncode != 0 or not os.path.exists(args.out):
|
||||
print("[!] SPI dump failed", file=sys.stderr)
|
||||
print(proc.stderr, file=sys.stderr)
|
||||
return 1
|
||||
size = os.path.getsize(args.out)
|
||||
print(json.dumps({"dump": args.out, "bytes": size}, indent=2))
|
||||
print("[*] decode offline with: chipsec_util uefi decode " + args.out, file=sys.stderr)
|
||||
return 0
|
||||
|
||||
|
||||
def main() -> int:
|
||||
p = argparse.ArgumentParser(description="CHIPSEC firmware-posture audit helper.")
|
||||
sub = p.add_subparsers(dest="cmd", required=True)
|
||||
|
||||
b = sub.add_parser("baseline", help="run full chipsec_main and summarize")
|
||||
b.add_argument("--log", help="CHIPSEC log file path")
|
||||
b.add_argument("--json", help="write parsed JSON report here")
|
||||
b.set_defaults(func=cmd_baseline)
|
||||
|
||||
m = sub.add_parser("module", help="run one or the core security modules")
|
||||
m.add_argument("--name", help="specific module, e.g. common.bios_wp (default: core set)")
|
||||
m.set_defaults(func=cmd_module)
|
||||
|
||||
d = sub.add_parser("dump", help="dump SPI flash (read-only)")
|
||||
d.add_argument("--out", default="rom.bin")
|
||||
d.set_defaults(func=cmd_dump)
|
||||
|
||||
args = p.parse_args()
|
||||
return args.func(args)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
Reference in New Issue
Block a user