Skip to main content
Glama

maldoc_analyze

Analyze suspicious Office documents to extract VBA macros, identify auto-execution triggers, detect obfuscation patterns, and find malicious indicators without executing payloads.

Instructions

Full malware document analysis pipeline.

  1. oledump.py — list OLE streams, identify macro-containing streams (marked 'M')

  2. olevba — extract VBA macro code

  3. Identify auto-execution triggers (Document_open, AutoOpen, Workbook_Open)

  4. Look for obfuscation patterns and base64 payloads

  5. Search for PowerShell, WMI, and shell execution indicators

Returns: {"ole_streams": str, "vba_macros": str, "auto_exec_triggers": [str], "suspicious_strings": [str], "iocs": [str]}.

Side effects: Read-only file analysis. Does NOT execute any payloads.

Errors: Requires oledump.py and olevba (pip install oletools).

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
file_pathYesPath to the suspicious OLE document (.doc, .xls, .bin)

Implementation Reference

  • The implementation of the maldoc_analyze tool, including registration and the handler logic that runs oledump/olevba and parses the results.
    server.tool(
      "maldoc_analyze",
      "Full malware document analysis pipeline.\n\n1. oledump.py — list OLE streams, identify macro-containing streams (marked 'M')\n2. olevba — extract VBA macro code\n3. Identify auto-execution triggers (Document_open, AutoOpen, Workbook_Open)\n4. Look for obfuscation patterns and base64 payloads\n5. Search for PowerShell, WMI, and shell execution indicators\n\nReturns: {\"ole_streams\": str, \"vba_macros\": str, \"auto_exec_triggers\": [str], \"suspicious_strings\": [str], \"iocs\": [str]}.\n\nSide effects: Read-only file analysis. Does NOT execute any payloads.\n\nErrors: Requires oledump.py and olevba (pip install oletools).",
      {
        file_path: z
          .string()
          .describe(
            "Path to the suspicious OLE document (.doc, .xls, .bin)"
          ),
      },
      async ({ file_path }) => {
        const { abspath: fpath, error } = validateFile(file_path);
        if (error) {
          return { content: [{ type: "text", text: JSON.stringify({ error }) }] };
        }
    
        // Step 1: OLE stream listing
        const oledumpRes = await runShell(
          `oledump.py '${fpath}' 2>/dev/null || python3 -m oletools.oledump '${fpath}' 2>/dev/null || echo 'oledump not available'`
        );
    
        // Step 2: VBA macro extraction
        const olevbaRes = await runShell(
          `olevba '${fpath}' 2>/dev/null || python3 -m oletools.olevba '${fpath}' 2>/dev/null || echo 'olevba not available'`
        );
    
        // Step 3: Find auto-execution triggers
        const autoTriggers: string[] = [];
        const triggerPatterns = [
          "Document_Open",
          "AutoOpen",
          "Auto_Open",
          "Workbook_Open",
          "AutoExec",
          "AutoClose",
          "Document_Close",
        ];
        const vbaText = olevbaRes.stdout;
        for (const trigger of triggerPatterns) {
          if (vbaText.toLowerCase().includes(trigger.toLowerCase())) {
            autoTriggers.push(trigger);
          }
        }
    
        // Step 4: Suspicious string detection
        const suspicious: string[] = [];
        const susPatterns = [
          "Shell",
          "WScript",
          "PowerShell",
          "cmd.exe",
          "cmd /c",
          "Exec",
          "CreateObject",
          "win32_Process",
          "WMI",
          "base64",
          "FromBase64String",
          "Convert",
          "Invoke-Expression",
          "IEX",
          "DownloadString",
          "DownloadFile",
          "Net.WebClient",
          "BitsTransfer",
          "certutil",
          "mshta",
          "regsvr32",
          "rundll32",
          "cscript",
          "wscript",
        ];
        for (const pat of susPatterns) {
          if (vbaText.toLowerCase().includes(pat.toLowerCase())) {
            suspicious.push(pat);
          }
        }
    
        // Step 5: Extract IOCs (URLs, IPs)
        const urls = Array.from(
          vbaText.matchAll(/https?:\/\/[^\s"'>]+/g),
          (m) => m[0]
        );
        const ips = Array.from(
          vbaText.matchAll(/\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b/g),
          (m) => m[0]
        );
        const iocs = Array.from(new Set([...urls, ...ips]));
    
        const result = {
          ole_streams: oledumpRes.stdout.slice(0, 3000),
          vba_macros: vbaText.slice(0, 5000),
          auto_exec_triggers: autoTriggers,
          suspicious_strings: suspicious,
          iocs: iocs.slice(0, 50),
          analysis_summary: {
            has_macros: autoTriggers.length > 0 || vbaText.includes("VBA"),
            has_auto_exec: autoTriggers.length > 0,
            has_suspicious_apis: suspicious.length > 0,
            has_network_iocs: iocs.length > 0,
          },
        };
    
        return { content: [{ type: "text", text: JSON.stringify(result) }] };
      }
    );

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/operantlabs/operant-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server