.. _examples: ==================== Examples and Recipes ==================== The following examples are drawn from real benchmark post-processing code in the Xylok Security Suite. Each example is labeled with the benchmark and check ID it was sourced from so you can look up the full context if needed. (Examples may vary from the current scripts over time, but are still relevant.) Windows Registry Check ---------------------- A very common pattern on Windows benchmarks is to query a registry value with ``reg query`` and then use a regular expression to verify the expected value exists and is set correctly. Early ``return`` guard clauses keep each branch independent and flat, handling the "key not found," "key found and correct," and "key found but wrong" cases without nested ``if / elif / else``. **Source:** ``microsoft_windows_11_stig / WN11-CC-000110`` — "Printing over HTTP must be prevented." .. code:: python import re valuenotfound = "The system was unable to find the specified registry key or value." goodvalue = r"DisableHTTPPrinting\s+REG_DWORD\s+0x1" if re.search(valuenotfound, ctx.raw, re.IGNORECASE): print("The registry value does not exist.") ctx.recommend_noncompliant("The system is not configured to prevent printing over HTTP.") return if re.search(goodvalue, ctx.raw, re.IGNORECASE): print(ctx.raw) ctx.recommend_compliant("The system is configured to prevent printing over HTTP.") return print(ctx.raw) ctx.recommend_noncompliant("The system is not configured to prevent printing over HTTP.") IIS MIME Type Check with Utility Function ----------------------------------------- This example demonstrates several features in one short script: using a :mod:`utility module ` (:func:`utils.windows.powershell.ps_list_cleanup`) to parse PowerShell list output, an early ``return`` guard clause for a not-applicable condition, and iterating over cleaned results to build a human-readable list of non-compliant items. **Source:** ``iis_10-0_server_stig / IIST-SV-000124`` — "The IIS 10.0 web server must have MIME types that invoke OS shell programs disabled." .. code:: python from utils.windows.powershell import ps_list_cleanup if "WSUS installed" in ctx.raw: ctx.recommend_na("WSUS installed, which makes this check Not Applicable.") return # Split the results with a little cleanup extension_list = ps_list_cleanup(ctx.raw, "\n\n") print(ctx.raw) if not extension_list: ctx.recommend_compliant("All MIME Types that invoke OS shell programs have been disabled.") return nc_extensions = [] for extension_result in extension_list: extension_name = extension_result.split(" : ", 1)[1].strip() nc_extensions.append(extension_name) ctx.recommend_noncompliant( f"The following MIME Types that invoke OS shell programs have not been disabled: {', '.join(nc_extensions)}" ) Cisco IOS Configuration Parsing with NetworkParse ------------------------------------------------- The :mod:`networkparse` module makes it easy to parse structured network device configurations. In this case, it's used to filter the running configuration for AAA-related lines and local user definitions, then prints them in a tree display for the reviewer. This examples doesn't provide any particular recommendation and will appear as unreviewed to the user, but with just the filtered lines displayed. **Source:** ``cisco_ios-xr_router_ndm_stig / CISC-ND-000490`` — "The Cisco router must be configured with only one local account to be used as the account of last resort." .. code:: python # Here we directly import networkparse, but it's also available at `utils.networkparse` from networkparse import parse config = parse.ConfigIOS(ctx.raw) print("🔎 Finding all AAA related configuration lines:") print(config.filter(".*aaa.*", depth=None).tree_display()) print() print("🔎 Finding all local users:") for user in config.filter("username.*"): print(user.tree_display()) Complex Example and Cleanup --------------------------- This example demonstrates defining a function within the script for local complex logic that isn't shared with other scripts, as recommended in the :ref:`concepts` Best Practices. The `active_lines(raw)` helper normalizes grep output (stripping file-path prefixes, skipping comments and blank lines) and is called in multiple places. However, the original script also has some deep nesting, which makes the logic harder to follow. After the original code, we show a refined version which uses early returns to simplify some of the logic. **Source:** ``can_ubuntu_22-04_lts_stig / UBTU-22-653020`` — "Ubuntu 22.04 LTS audit event multiplexor must be configured to offload audit logs onto a different system from the system being audited." Original: Linux Audit Offload Check ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .. code:: python compliance = True complianceComment = "" ### STIG VALUES ### PKG_SENTINEL = "Not installed" REQUIRED_ACTIVE = "yes" ### STIG VALUES ### cmdOutput = ctx.ics_split()[1:] # [0]=dpkg, [1]=grep active, [2]=grep remote_server print("Checking that audit offloading via audispd is configured:") # Helper: normalize grep output lines, strip file prefixes and comments def active_lines(raw): if raw is None: return [] lines = [] for ln in raw.splitlines(): ln = ln.rstrip() if not ln.strip(): continue # strip "/path:content" prefix from grep -R style if ":" in ln and ln.split(":",1)[0].startswith("/"): ln = ln.split(":",1)[1].lstrip() if ln.lstrip().startswith("#"): continue lines.append(ln) return lines # 1) Package installed? if not cmdOutput or len(cmdOutput) < 3: compliance = False print("\N{cross mark} Missing outputs for package/active/remote_server checks.") complianceComment = ("Did not receive all three outputs. Ensure 'audispd-plugins' is installed, " "'active = yes' in /etc/audit/plugins.d/au-remote.conf, and " "'remote_server = ' in /etc/audit/audisp-remote.conf.") else: pkg_raw = (cmdOutput[0] or "") if PKG_SENTINEL in pkg_raw: compliance = False print("\N{cross mark} 'audispd-plugins' package is not installed.") complianceComment = ("'audispd-plugins' missing. Install it with " "'apt-get install audispd-plugins'.") else: # look for 'ii audispd-plugins' import re pkg_ok = False for ln in pkg_raw.splitlines(): if not ln.strip(): continue # strip possible "file:" prefix if ":" in ln and ln.split(":",1)[0].startswith("/"): ln = ln.split(":",1)[1].lstrip() m = re.match(r'^\s*([a-z]{2})\s+(\S+)', ln.lower()) if m and m.group(1) == "ii" and (m.group(2) == "audispd-plugins" or m.group(2).startswith("audispd-plugins:")): pkg_ok = True break if pkg_ok: print("\N{left-pointing magnifying glass} audispd-plugins package is installed.") else: compliance = False print("\N{cross mark} audispd-plugins not in installed state.") complianceComment = ("'audispd-plugins' is not fully installed (dpkg state not 'ii'). " "Install with 'apt-get install audispd-plugins'.") # 2) au-remote active? if compliance: active_raw = cmdOutput[1] or "" act_lines = active_lines(active_raw) if not act_lines: compliance = False print("\N{cross mark} No active 'active =' line found in au-remote.conf.") complianceComment = ("Missing or commented 'active = yes' in " "/etc/audit/plugins.d/au-remote.conf.") else: # evaluate last effective assignment eff = None for ln in act_lines: if ln.lower().startswith("active"): parts = [p.strip() for p in ln.split("=",1)] if len(parts) == 2: eff = parts[1].lower() if eff == REQUIRED_ACTIVE: print("\N{left-pointing magnifying glass} au-remote plugin is active (active = yes).") else: compliance = False print("\N{cross mark} 'active' not set to 'yes' in au-remote.conf.") complianceComment = ("'/etc/audit/plugins.d/au-remote.conf' must contain " "'active = yes' (uncommented).") # 3) remote_server valid and not loopback/invalid if compliance: rs_raw = cmdOutput[2] or "" rs_lines = active_lines(rs_raw) if not rs_lines: compliance = False print("\N{cross mark} No active 'remote_server =' line found.") complianceComment = ("Missing or commented 'remote_server = ' in " "/etc/audit/audisp-remote.conf.") else: remote_val = None for ln in rs_lines: if ln.lower().startswith("remote_server"): parts = [p.strip() for p in ln.split("=",1)] if len(parts) == 2: remote_val = parts[1] if not remote_val: compliance = False print("\N{cross mark} Unable to parse remote_server value.") complianceComment = ("Invalid 'remote_server' assignment in " "/etc/audit/audisp-remote.conf.") else: # Validate IPv4 dotted-quad; reject loopback/0.0.0.0; (private ranges OK if a separate host) ipv4_ok = re.match(r'^\d{1,3}(\.\d{1,3}){3}$', remote_val) is not None if not ipv4_ok: compliance = False print("\N{cross mark} remote_server is not an IPv4 address.") complianceComment = ("'remote_server' must be a valid IPv4 address " "(e.g., 192.0.2.10), not: '{}'.".format(remote_val)) else: octets = [int(x) for x in remote_val.split(".")] valid_octets = all(0 <= o <= 255 for o in octets) loopback = (octets[0] == 127) unspecified = (remote_val == "0.0.0.0") if not valid_octets or loopback or unspecified: compliance = False print("\N{cross mark} remote_server is invalid or loopback/unspecified.") complianceComment = ("'remote_server' must be a valid non-loopback IPv4 address; " f"found '{remote_val}'.") else: print("\N{white heavy check mark} Remote offload configured (active=yes, remote_server set).") complianceComment = (f"audisp remote offload enabled; remote_server = {remote_val}.") # 6) Final Recommendation if compliance: recommend_compliant(complianceComment.strip()) else: recommend_noncompliant(complianceComment.strip()) Refactored ~~~~~~~~~~ The version above works, but violates several :ref:`concepts` Best Practices. The refactored version below addresses those: .. code:: python import re ### STIG VALUES ### PKG_SENTINEL = "Not installed" REQUIRED_ACTIVE = "yes" ### STIG VALUES ### # Helper: normalize grep output lines, strip file prefixes and comments def active_lines(raw): if raw is None: return [] lines = [] for ln in raw.splitlines(): ln = ln.rstrip() if not ln.strip(): continue # strip "/path:content" prefix from grep -R style if ":" in ln and ln.split(":", 1)[0].startswith("/"): ln = ln.split(":", 1)[1].lstrip() if ln.lstrip().startswith("#"): continue lines.append(ln) return lines cmdOutput = ctx.ics_split()[1:] # [0]=dpkg, [1]=grep active, [2]=grep remote_server print("Checking that audit offloading via audispd is configured:") # 1) All three command outputs present? if not cmdOutput or len(cmdOutput) < 3: print("\N{cross mark} Missing outputs for package/active/remote_server checks.") ctx.recommend_noncompliant( "Did not receive all three outputs. Ensure 'audispd-plugins' is installed, " "'active = yes' in /etc/audit/plugins.d/au-remote.conf, and " "'remote_server = ' in /etc/audit/audisp-remote.conf." ) return # 2) Package installed? pkg_raw = cmdOutput[0] or "" if PKG_SENTINEL in pkg_raw: print("\N{cross mark} 'audispd-plugins' package is not installed.") ctx.recommend_noncompliant( "'audispd-plugins' missing. Install it with 'apt-get install audispd-plugins'." ) return pkg_ok = False for ln in pkg_raw.splitlines(): if not ln.strip(): continue if ":" in ln and ln.split(":", 1)[0].startswith("/"): ln = ln.split(":", 1)[1].lstrip() m = re.match(r'^\s*([a-z]{2})\s+(\S+)', ln.lower()) if m and m.group(1) == "ii" and ( m.group(2) == "audispd-plugins" or m.group(2).startswith("audispd-plugins:") ): pkg_ok = True break if not pkg_ok: print("\N{cross mark} audispd-plugins not in installed state.") ctx.recommend_noncompliant( "'audispd-plugins' is not fully installed (dpkg state not 'ii'). " "Install with 'apt-get install audispd-plugins'." ) return print("\N{left-pointing magnifying glass} audispd-plugins package is installed.") # 3) au-remote active? active_raw = cmdOutput[1] or "" act_lines = active_lines(active_raw) if not act_lines: print("\N{cross mark} No active 'active =' line found in au-remote.conf.") ctx.recommend_noncompliant( "Missing or commented 'active = yes' in /etc/audit/plugins.d/au-remote.conf." ) return eff = None for ln in act_lines: if ln.lower().startswith("active"): parts = [p.strip() for p in ln.split("=", 1)] if len(parts) == 2: eff = parts[1].lower() if eff != REQUIRED_ACTIVE: print("\N{cross mark} 'active' not set to 'yes' in au-remote.conf.") ctx.recommend_noncompliant( "'/etc/audit/plugins.d/au-remote.conf' must contain " "'active = yes' (uncommented)." ) return print("\N{left-pointing magnifying glass} au-remote plugin is active (active = yes).") # 4) remote_server valid and not loopback/invalid rs_raw = cmdOutput[2] or "" rs_lines = active_lines(rs_raw) if not rs_lines: print("\N{cross mark} No active 'remote_server =' line found.") ctx.recommend_noncompliant( "Missing or commented 'remote_server = ' in /etc/audit/audisp-remote.conf." ) return remote_val = None for ln in rs_lines: if ln.lower().startswith("remote_server"): parts = [p.strip() for p in ln.split("=", 1)] if len(parts) == 2: remote_val = parts[1] if not remote_val: print("\N{cross mark} Unable to parse remote_server value.") ctx.recommend_noncompliant( "Invalid 'remote_server' assignment in /etc/audit/audisp-remote.conf." ) return # Validate IPv4 dotted-quad; reject loopback/0.0.0.0 ipv4_ok = re.match(r'^\d{1,3}(\.\d{1,3}){3}$', remote_val) is not None if not ipv4_ok: print("\N{cross mark} remote_server is not an IPv4 address.") ctx.recommend_noncompliant( f"'remote_server' must be a valid IPv4 address (e.g., 192.0.2.10), not: '{remote_val}'." ) return octets = [int(x) for x in remote_val.split(".")] valid_octets = all(0 <= o <= 255 for o in octets) loopback = octets[0] == 127 unspecified = remote_val == "0.0.0.0" if not valid_octets or loopback or unspecified: print("\N{cross mark} remote_server is invalid or loopback/unspecified.") ctx.recommend_noncompliant( f"'remote_server' must be a valid non-loopback IPv4 address; found '{remote_val}'." ) return print("\N{white heavy check mark} Remote offload configured (active=yes, remote_server set).") ctx.recommend_compliant(f"audisp remote offload enabled; remote_server = {remote_val}.") Discussion of Changes ~~~~~~~~~~~~~~~~~~~~~ The following changes were made to bring the script in line with the :ref:`concepts` Best Practices: *1. `ctx.` prefix on all recommendation calls.** The original code called bare `recommend_compliant()` and `recommend_noncompliant()` — deprecated globals that exist for backward compatibility. Every recommendation now uses `ctx.recommend_compliant()` / `ctx.recommend_noncompliant()`. **2. Early `return` instead of `compliance` flag tracking.** The original code carried a `compliance` boolean and a `complianceComment` string through every sub-check, then made a single recommendation at the very end. This required `if compliance:` guards before each sub-check, creating nesting. The refactored code calls `ctx.recommend_noncompliant()` and `return`\ s immediately on each failure branch. This eliminates both tracking variables entirely and flattens the control flow. **3. Imports moved to the top.** The original placed `import re` mid-function, inside the package check block. Python allows this, but we generally recommend imports at the top of the module for readability. **4. Helper function moved above the main logic.** The `active_lines()` helper was defined after the first `print()` in the original. It now appears right after the STIG-values block, before any main-line code runs. This follows the convention of defining helpers before they are called and keeps the top-to-bottom reading order clean: constants → helpers → main logic. **5. Eliminated deeply nested `if`/`else` blocks.** The original code had up to **five** levels of nesting (the `else` of the output-count check → the `else` of the sentinel check → the `if compliance:` guard → the `else` of the empty-lines check → the `else` of the IPv4 format check). Each sub-check now sits at the **same** top-level indentation. On failure, the script prints its message, makes its recommendation, and returns — no nesting required. The happy path falls through to the final `ctx.recommend_compliant()` call. **6. Consistent f-string usage.** The original mixed `.format()` and f-strings in the `remote_server` error messages. All string interpolation now uses f-strings.