Skip to content

Security: unauthenticated OS command injection via directive query target #383

Description

@bronson-calif

Summary

The builtin directive templates for the shell-backed platforms interpolate the unauthenticated query target into a command string that is executed by a POSIX shell. A shell metacharacter in the query target breaks out of the intended argument, so a single unauthenticated POST /api/query can run arbitrary OS commands on the managed router as the SSH login user.

Version

v2.0.0 through current main (v2.0.4).

Affected platforms

Backends whose command string is parsed by a shell:

  • FRR, BIRD, OpenBGPD — mapped to device_type="linux_ssh", so netmiko delivers the command to a host bash shell.
  • TNSR — the directive runs dataplane shell sudo vtysh -c "...", which drops to a host shell.

The non-shell NOS platforms (Cisco/Arista/Juniper/Nokia/Huawei/MikroTik/VyOS) are not shell-injectable, but an embedded newline in the target survives netmiko's rstrip-only normalize_cmd and is executed as a second CLI line.

Root cause

Two things combine:

  1. Construct.format() substitutes the target with a bare str.format() — no shell escaping:
    # hyperglass/execution/drivers/_construct.py
    return command.format(target=self.target, mask=mask, **attrs)
    with templates like 'vtysh -c "show bgp ipv4 unicast regexp {target}"'.
  2. The default condition="*" rule compiles to re.compile(".+").match() (hyperglass/models/directive.py), which is start-anchored and matches any non-empty string, so no shell metacharacter is rejected.

A " in the target closes the quote and a following ; / ` / $(...) reaches bash. OpenBGPD's template (bgpctl show rib inet as {target}) is unquoted, so a bare ; injects directly.

Steps to Reproduce

  1. Deploy hyperglass with an FRR (or BIRD/OpenBGPD/TNSR) device — the default builtin BGP AS Path directive.
  2. Send an unauthenticated query whose target contains a shell metacharacter, e.g. a queryTarget of:
    _65000"; id; echo "
    
  3. The constructed command becomes vtysh -c "show bgp ipv4 unicast regexp _65000"; id; echo "", and bash executes the injected id.

Expected Behavior

The query target should be treated as a single, literal argument to the device command; shell metacharacters in it should have no effect beyond (at most) failing to match.

Observed Behavior

The injected command executes on the router host. The HTTP response still returns the legitimate show bgp output, so the injection is not visible in the query result.

Fix

Proposed in #382 — shell-quote the target at construction for shell-backed platforms, and reject ASCII control characters at the query model (for the newline vector on non-shell platforms).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions