Skip to content

resolved DNSSEC validation can be bypassed by MITM #25676

@AgentOak

Description

@AgentOak

systemd version the issue has been seen with

251.8-1-manjaro

Used distribution

Manjaro

Linux kernel version used

5.15.81-1-MANJARO

CPU architectures issue was seen on

x86_64

Component

systemd-resolved

Expected behaviour you didn't see

When DNSSEC=yes is set and querying a DNSSEC-enabled domain, systemd-resolved should only accept records that are signed correctly.

Unexpected behaviour you saw

systemd-resolved accepts records of DNSSEC-signed domains even when they have no signature, allowing man-in-the-middles (or the upstream DNS resolver) to manipulate records.

Please note that I have repeatedly tried to report this issue to the systemd-security mailing list. I sent a mail with the details and reproduction steps to the systemd-security address on Oct 6th, Oct 14th and Oct 22nd. I first received a reply on Oct 24th from Lennart Poettering, asking for some basic system information, which I provided on the same day. Then I received no further reply, so I sent the report one more time to systemd-security on Nov 7th. The next day Poettering replied to my previous mail, asking for a debug log, but not directly acknowledging the issue. I sent debug logs on Nov 10th and haven't heard back from anyone since then.

Steps to reproduce the problem

The issue can be reproduced with an unbound server and a typetransparent local-zone to simulate an attacker modifying select records. cloudflare.net is used as an example domain since it is signed and valid. In this example, the DNS server is run on 192.168.1.1 and the systemd client has any address in the same /24 network.

unbound.conf:

server:
  # Allow running unbound unprivileged
  username: ""
  use-syslog: no
  chroot: ""
  pidfile: ""

  interface: 0.0.0.0
  port: 10053
  access-control: 192.168.1.1/24 allow

  local-zone: www.cloudflare.net typetransparent
  local-data: "www.cloudflare.net. 3600 IN A 1.2.3.4"

forward-zone:
  name: .
  forward-addr: 1.1.1.1
  forward-addr: 1.0.0.1
  forward-first: no
  1. On the "attacker" machine, install unbound and run unbound -d -v -c unbound.conf.
  2. On the machine running systemd-resolved, run sudo systemd-resolve --set-dns 192.168.1.1:10053 --set-dnssec yes --interface enp0s3. (Replace IP and interface name accordingly).
  3. Run resolvectl status to confirm our DNS server is used and output contains DNSSEC=yes/supported.
  4. Run resolvectl query cloudflare.net which should produce the correct reply and Data is authenticated: yes, confirming that the domain is DNSSEC-signed.
  5. Run resolvectl query www.cloudflare.net:
$ resolvectl query www.cloudflare.net
www.cloudflare.net: 1.2.3.4                    -- link: enp0s3

-- Information acquired via protocol DNS in 25.6ms.
-- Data is authenticated: no; Data was acquired via local or encrypted transport: no
-- Data from: network

systemd-resolved accepts the bogus response. Running dig @127.0.0.53 www.cloudflare.net also shows the status is NOERROR. When resolved is configured as system resolver (e.g. through /etc/resolv.conf), curl -v http://www.cloudflare.net tries to connect to 1.2.3.4, showing that applications are successfully tricked with the manipulated record.

Note that resolved does state the data is unauthenticated and also does not set the AD bit when queried on 127.0.0.53.

Repeat the test but replace typetransparent with static in the unbound configuration. In this case, resolved rejects the response as expected:

$ resolvectl query www.cloudflare.net
www.cloudflare.net: resolve call failed: DNSSEC validation failed: no-signature

(Note that due to another bug #24827, resolved will still reply with the records on 127.0.0.53, but it has status: SERVFAIL, so applications generally won't use this answer)

The difference is that static replaces all data for the www.cloudflare.net domain, whereas typetransparent only replaces the A record(s). Both strip the RRSIG records from affected queries.

My knowledge on DNS isn't great, but as far as I know no unsigned record should be allowed anywhere under the zone cloudflare.net, unless there was an insecure delegation (NS record without corresponding DS record).
However, it appears only signatures of some types of records actually matter to resolved, for example the SOA record. The RRSIG signatures on A/AAAA (and probably more) records can simply be stripped and resolved will accept the data without ensuring its validity.

Additional program output to the terminal or log subsystem illustrating the issue

systemd-resolved debug logs, including all output after running `resolvectl query www.cloudflare.net` are posted in this gist, separate for the typetransparent and the static test case: https://gist.github.com/AgentOak/11c64ff8701c4cd853d6b99382a40704

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions