Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Information Disclosure Issue: Add feature to disable wildcard lookups #4984

Closed
micahhausler opened this issue Nov 15, 2021 · 17 comments
Closed

Comments

@micahhausler
Copy link

micahhausler commented Nov 15, 2021

Opening this as a public issue, as there are already public discussions and integration into penetration testing tooling.

CoreDNS's wildcard feature (specifically wildcards in Kubernetes) present an information disclosure.

CoreDNS has several plugins that support wildcard lookups, including the file, etcd, and kubernetes plugins. In environments such as Kubernetes where Service Discovery is desired, full enumeration of Services, Namespaces, and Endpoint IPs is possible even when Kubernetes API permissions or authentication is denied.

Administrators can disable the mounting of Kubernetes Service Account tokens and deny the pod any identity in the Kubernetes API. They can disable Docker links compatibility to limit same-namespace service discovery in a pod. They can also use spec.dnspolicy or spec.dnsConfig to use alternate nameservers instead of CoreDNS, but that prevents any in-cluster service discovery.

For an administrator who considers namespaces, service names, or pod IPs (or the number of pod IPs behind a service) to be confidential and still wants service discovery, they have no way to disable wildcard service listing in their cluster.

This is particularly concerning if anyone were to run untrusted code in a cluster where that code executes lookups against CoreDNS. Barriers such as node-affinity/taints and tolerations, or encapsulation mechanisms like Google's gVisor or Kata containers are of no benefit if DNS requests are sent to CoreDNS.

If this were considered a vulnerability, my initial CVSS estimate would rate it as a Medium 4.3

What would you like to be added:

I propose a new configuration for the Kubernetes plugin to disable wildcard lookups. For backward compatibility, wildcards may need to be on by default, but a deprecation path where wildcards are disabled by default would be greatly beneficial.

CC: @JayBeale @raesene

@johnbelamaric
Copy link
Member

Seems reasonable to me. Though, even with wildcards disabled, you can still get service IPs and pods IPs (for headless services at least) from DNS, without access to the namespaces via RBAC.

@chrisohaver is it possible to block these with the existing acl plugin? I suspect not. Maybe with the firewall one?

Another mitigation might be via rewrite - I suspect you could rewrite any name with a '*' in it to a strip it out.

@chrisohaver
Copy link
Member

I'm not opposed at all to removing the "wildcard query" feature. IMO it's a useless feature. It has occasionally been a PITA to maintain, impacting tests and corner cases. Wildcard queries are also not a "real DNS" thing. In the case of kubernetes, it's not part of the Kubernetes service discovery spec, and I suspect it was only present due to it being inherited from the etcd plugin from which it was originally based. I would not be sad to see it go.

@chrisohaver
Copy link
Member

chrisohaver commented Nov 15, 2021

I think you could create a * domain server block to block the namespace level ... e.g.

*.svc.cluster.local *.pod.cluster.local {
    [nodata response]
}

But that still leaves service name enumeration exposed via SRV queries.

the template plugin could help here too... matching for wildcard queries and returning a nodata response.

@chrisohaver
Copy link
Member

chrisohaver commented Nov 15, 2021

For the Kubernetes use case: the following template plugin config should work to block all wildcard queries (returning a nodata response)

. {
  ...
  template IN ANY cluster.local {
    match "^\*(\..*)*\.cluster\.local\.$"
    fallthrough
  }
  kubernetes cluster.local ...
  ...
}

@chrisohaver
Copy link
Member

chrisohaver commented Nov 15, 2021

It could of course be generalized to block all wildcard queries for all domains, not just cluster.local ...

  template IN ANY . {
    match "^\*(\..*)*\.$"
    fallthrough
  }

@chrisohaver
Copy link
Member

IIRC, any is also considered a wildcard - so that would need to be added to the regex ...

  template IN ANY . {
    match "^(\*|any)(\..*)*\.$"
    fallthrough
  }

@chrisohaver
Copy link
Member

... and I think we may allow for wildcard labels to be "in the middle" of a query ... so ...

  template IN ANY . {
    match "^(.*\.)*(\*|any)(\..*)*\.$"
    fallthrough
  }

@chrisohaver
Copy link
Member

All that said, wildcard query support is fundamentally incompatible with actual queries for wildcard records (we can't tell the difference between a wildcard query, and a query for a wildcard record - they look the same). So you probably should only apply this to the domains that can feature wildcard query support - e.g. in a k8s cluster cluster.local. - else you'd block wildcard record lookups to upstream.

You could also limit the template blockage to just SRV records, since that is where the bulk of the exposure lies. Though, you'd still see externalName services that target cluster services (not sure if there is a use case for that, but it can be done).

@miekg
Copy link
Member

miekg commented Nov 22, 2021

... actual queries for wildcard records ...

this doesn't exist in the dns, you query a name, the zone data contains a '*'. then it's wildcard lookup.

'*' should never exist in a query name - it's allowed though, then it's an asterisk label

@chrisohaver
Copy link
Member

chrisohaver commented Nov 22, 2021

... actual queries for wildcard records ...

this doesn't exist in the dns, you query a name, the zone data contains a '*'. then it's wildcard lookup.

'*' should never exist in a query name - it's allowed though, then it's an asterisk label

What I’m referring to is lookups of the wild card records themselves (yes - in this case the asterix is just a plain label), iirc there are examples in the RFCs. In those cases the wild card record itself is returned.

Edit: I could not find query examples, but from RFC 1034 ...

A * label appearing in a query name has no special effect, but can be
used to test for wildcards in an authoritative zone; such a query is the
only way to get a response containing RRs with an owner name with * in
it. The result of such a query should not be cached.

I didn't recall the part about not caching it. I would guess we do cache these, but it's a "should not" not a "MUST not".

@miekg
Copy link
Member

miekg commented Nov 25, 2021 via email

@chrisohaver
Copy link
Member

[ Quoting @.*> in "Re: [coredns/coredns] Information D..." ]
'
' should never exist in a query name - it's allowed though, then it's an asterisk label What I’m referring to is lookups of the wild card records themselves, iirc there are examples in the RFCs. In those cases the wild card record itself is returned.
nope, it's not a wildcard then, but an asterisk label, like 'sub.
.example.' as given in the RFC

I agree, it’s a plain label. We are saying the same thing.

@chrisohaver
Copy link
Member

chrisohaver commented Nov 25, 2021

To be clear, by “actual queries for wild card records”, I meant a query with a * in the name, made with intent of confirming the existence of the record in the zone defining the wild card (the wild card record). This is a just normal query for a record and the response is just a normal record, with no wildcard synthesis involved. This case is mentioned in the rfc, quoted above.

@github-actions
Copy link

This issue is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 7 days

@github-actions github-actions bot added Stale and removed Stale labels Jan 27, 2022
@enj
Copy link

enj commented Jan 31, 2022

I have an AI to help write an advisory for this issue. Hoping to get to it soon.

@chrisohaver
Copy link
Member

Wildcard lookups are no longer supported in 1.9.0.

For earlier versions, see the template plugin solution above.

@JayBeale
Copy link

I'm sorry that I missed this @micahhausler. It's a great idea to remove the functionality, which is too useful to bad actors, and lacks a common use case for expected workloads.

Thanks for making this happen @micahhausler and @chrisohaver!

@enj, if I can help (or maybe @raesene is better than me here) or ghost-write a first draft for you, I'm game.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

6 participants