Lookup Binary
detection_lookup_binaryCheck if a binary is a known LOLBAS (Windows) or GTFOBins (Linux) living-off-the-land binary, returning risk level, abuse categories, and MITRE ATT&CK technique IDs for detection enrichment.
Instructions
Check if a binary is a known LOLBAS (Windows) or GTFOBins (Linux) living-off-the-land binary.
Provide the filename (e.g., 'certutil.exe', 'curl', 'python'). Returns risk level, abuse categories, MITRE ATT&CK technique IDs, description, and source. Searches both LOLBAS (Windows) and GTFOBins (Linux) datasets. If not found in either, returns {found: false} with a suggestion.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| filename | Yes |
Output Schema
| Name | Required | Description | Default |
|---|---|---|---|
No arguments | |||
Implementation Reference
- mcp_server/server.py:84-139 (handler)The handler function for detection_lookup_binary. Accepts a filename string, strips path/whitespace, normalizes case, searches both LOLBAS (Windows) and GTFOBins (Linux) datasets, and returns found status with risk level, categories, MITRE IDs, description, and source. If not found in either, returns {found: false} with a suggestion.
def detection_lookup_binary(filename: str) -> dict[str, Any]: """Check if a binary is a known LOLBAS (Windows) or GTFOBins (Linux) living-off-the-land binary. Provide the filename (e.g., 'certutil.exe', 'curl', 'python'). Returns risk level, abuse categories, MITRE ATT&CK technique IDs, description, and source. Searches both LOLBAS (Windows) and GTFOBins (Linux) datasets. If not found in either, returns {found: false} with a suggestion. """ filename_lower = filename.lower().strip() # Strip path if provided if "\\" in filename_lower or "/" in filename_lower: filename_lower = filename_lower.replace("\\", "/").split("/")[-1] results = [] # Search LOLBAS (Windows) for row in _get_lolbas(): if row.get("filename", "").lower() == filename_lower: results.append({ "source": "lolbas", "binary_name": row.get("binary_name", ""), "primary_path": row.get("primary_path", ""), "categories": row.get("categories", "").split("|") if row.get("categories") else [], "mitre_ids": row.get("mitre_ids", "").split("|") if row.get("mitre_ids") else [], "risk": row.get("risk", ""), "description": row.get("description", ""), }) # Search GTFOBins (Linux) for row in _get_gtfobins(): if row.get("filename", "").lower() == filename_lower: results.append({ "source": "gtfobins", "binary_name": row.get("binary_name", ""), "primary_path": row.get("primary_path", ""), "categories": row.get("categories", "").split("|") if row.get("categories") else [], "mitre_ids": row.get("mitre_ids", "").split("|") if row.get("mitre_ids") else [], "risk": row.get("risk", ""), "description": row.get("description", ""), }) if not results: return { "found": False, "filename": filename_lower, "suggestion": ( "Binary not in LOLBAS or GTFOBins datasets. " "Try without the file extension (e.g., 'notepad' instead of 'notepad.exe'), " "or use detection_search to search by keyword." ), } # If found in one source, return that; if both, return all matches if len(results) == 1: return {"found": True, **results[0]} return {"found": True, "matches": results} - mcp_server/server.py:75-83 (registration)The @mcp.tool() decorator that registers detection_lookup_binary as an MCP tool with annotations including title 'Lookup Binary', readOnlyHint=True, idempotentHint=True.
@mcp.tool( annotations={ "title": "Lookup Binary", "readOnlyHint": True, "destructiveHint": False, "idempotentHint": True, "openWorldHint": False, }, ) - mcp_server/server.py:34-58 (helper)Helper function _load_csv loads CSV lookup files from the lookups/ directory. Used to populate the LOLBAS and GTFOBins caches that detection_lookup_binary queries.
def _load_csv(filename: str) -> list[dict[str, str]]: """Load a CSV lookup file and return rows as list of dicts.""" filepath = LOOKUPS_DIR / filename if not filepath.exists(): return [] with open(filepath, "r", encoding="utf-8") as f: return list(csv.DictReader(f)) def _match_filename(pattern: str, value: str) -> bool: """Match with glob support (e.g., 'tomcat*.exe').""" return fnmatch(value.lower(), pattern.lower()) # Cache loaded data in memory (small files, fast startup) _lolbas_cache: list[dict[str, str]] | None = None _parent_child_cache: list[dict[str, str]] | None = None _gtfobins_cache: list[dict[str, str]] | None = None def _get_lolbas() -> list[dict[str, str]]: global _lolbas_cache if _lolbas_cache is None: _lolbas_cache = _load_csv("lolbas_binaries.csv") return _lolbas_cache - mcp_server/server.py:54-72 (helper)Helper functions _get_lolbas() and _get_gtfobins() that load and cache the CSV data. These are called by detection_lookup_binary to search each dataset.
def _get_lolbas() -> list[dict[str, str]]: global _lolbas_cache if _lolbas_cache is None: _lolbas_cache = _load_csv("lolbas_binaries.csv") return _lolbas_cache def _get_parent_child() -> list[dict[str, str]]: global _parent_child_cache if _parent_child_cache is None: _parent_child_cache = _load_csv("parent_child_baselines.csv") return _parent_child_cache def _get_gtfobins() -> list[dict[str, str]]: global _gtfobins_cache if _gtfobins_cache is None: _gtfobins_cache = _load_csv("gtfobins.csv") return _gtfobins_cache - mcp_server/server.py:43-45 (helper)Helper function _match_filename supporting glob-style matching using fnmatch. Used elsewhere but available as utility.
def _match_filename(pattern: str, value: str) -> bool: """Match with glob support (e.g., 'tomcat*.exe').""" return fnmatch(value.lower(), pattern.lower())