Skip to content

Linux.Remediation.Quarantine blocks the Velociraptor server when server_urls uses a hostname #4922

Description

@x86ButterOverflow

Summary

When Linux.Remediation.Quarantine is applied on a client whose server_urls are configured with a domain name (rather than a direct IP), the server address is not resolved in time. The nftables table and rules are still installed, but instead of allowing the Velociraptor frontend the policy ends up blocking it, so the client loses contact with the server. The built-in connectivity self-test then fails and the whole table is rolled back.

The problem does not occur when server_urls are configured with literal IP addresses.

Expected behaviour

The frontend is resolved and an allow-rule for the server address is installed, so the client stays connected while all other traffic is blocked.

Steps to reproduce

  1. Configure the client server_urls with a domain name, e.g.
    https://<your-domain>:8000/.
  2. Apply Linux.Remediation.Quarantine to the host.

Actual behaviour

The nftables rules are added, but the Velociraptor server is blocked rather than allowed, and the client loses its connection. The following lookup error is observed:

host: Lookup error : lookup <client-id>.<your-domain> on <dns-ip>:53: read udp <client-ip>:54802-><dns-ip>:53: i/o timeout

The DNS lookup times out, which suggests that resolution is attempted after the drop policy has already been installed (so DNS is already blocked by the time the frontend rule is built).

Likely cause

I'm not certain, but it looks like the server hostname is only resolved once the quarantine rules are already being applied i.e. after DNS has been blocked so the lookup times out and no valid allow-rule for the server is created.

LET add_to_out_chain(DstAddr, DstPort) = (..., 'ip', 'daddr', host(name=DstAddr)[0], ...)
LET extracted_config <= SELECT get_domain(URL=_value) AS DstAddr, ...

Workaround (to assess)

A custom version was created in which the frontend server is resolved first (up front, before any drop rule is applied). With that change the server stays reachable and the remaining traffic is blocked as intended.

extracted_config resolve up front and discard rows that don't resolve:

 // extract Velociraptor config for policy
-LET extracted_config <= SELECT get_domain(URL=_value) AS DstAddr,
+LET extracted_config <= SELECT host(name=get_domain(URL=_value))[0] AS DstAddr,
    get_port(URL=_value) AS DstPort,
    'VelociraptorFrontEnd' AS Description,
    _value AS URL
 FROM foreach(row=config.server_urls)
+WHERE DstAddr

add_to_in_chain use the resolved IP directly:

 LET add_to_in_chain(DstAddr, DstPort) = (pathToNFT, 'add', 'rule', 'inet',
-   TableName, 'inbound_chain', 'ip', 'saddr', host(name=DstAddr)[0],
+   TableName, 'inbound_chain', 'ip', 'saddr', DstAddr,
    'tcp', 'sport', '{', DstPort, '}', 'ct', 'state', 'established', 'accept')

add_to_out_chain same change on the outbound side:

 LET add_to_out_chain(DstAddr, DstPort) = (pathToNFT, 'add', 'rule', 'inet',
-   TableName, 'outbound_chain', 'ip', 'daddr', host(name=DstAddr)[0],
+   TableName, 'outbound_chain', 'ip', 'daddr', DstAddr,
    'tcp', 'dport', '{', DstPort, '}', 'ct', 'state', 'established,new', 'accept')

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions