Subject: [Acme] SSRF possible in ACME through http-01 using HTTP redirects (#136)

From: Blake Burkhart <[email-masked]>
Date: Thu, 9 Jun 2016 13:30:10 -0500

Posting this to the list for discussion:
https://github.com/ietf-wg-acme/acme/issues/136

Server side request forgery (SSRF) is possible through ACME when using
http-01 because an attacker can use HTTP 3xx redirects to make the ACME
verifier server perform an HTTP GET of any URL. Additionally, Boulder
helpfully includes (part) of the HTTP body in the detail field of
Unauthorized errors.

In theory, an HTTP GET of any URL is idempotent and won't actually affect
anything. But, if the ACME server returns any part of the HTTP body in
error messages (like Boulder does), an attacker could potentially read
sensitive data from internal servers.

Typical targets for SSRF would be metadata services (like 169.254.169.254
in AWS or OpenStack), any not publicly exposed HTTP interface of the
server's stack (like the HTTP API of the RabbitMQ management plugin), or
any other internal HTTP server on the server's private network.

Perhaps the IETF ACME protocol spec should acknowledge SSRF in its Security
Considerations? One recommendation could be to not allow connections to
internal network addresses. However, if someone wanted to use ACME for a
private intranet CA, correct firewalling like that is much harder. The spec
could also discourage including the HTTP body in an Unauthorized error's
detail field. Or at least don't include the HTTP body if a redirect was
followed.

Also, this is mostly mitigated by the actual implementation of Let's
Encrypt and Boulder. Notably, only 128 characters (maxResponseSize) of the
HTTP body are returned by Boulder
<https://github.com/letsencrypt/boulder/blob/51425cab815936d9f9ff2a2a6aef1aff75b5a042/va/va.go#L274>.
And it doesn't seem possible to get Let's Encrypt to access HTTP servers on
any port other than 80 or 443, even with a port number specified in the
redirect URL, which limits what an attacker could access.

(I reported this privately [email-masked] before creating this
GitHub issue. This is not an issue for Let's Encrypt.)

-- 
Blake

---

From: Jacob Hoffman-Andrews <[email-masked]>
Date: Thu, 9 Jun 2016 11:56:36 -0700

> Typical targets for SSRF would be metadata services (like
> 169.254.169.254 in AWS or OpenStack), any not publicly exposed HTTP
> interface of the server's stack (like the HTTP API of the RabbitMQ
> management plugin), or any other internal HTTP server on the server's
> private network.
>
> Perhaps the IETF ACME protocol spec should acknowledge SSRF in its
> Security Considerations? One recommendation could be to not allow
> connections to internal network addresses.
>
Yep, I think this makes sense to include in the Security Considerations.
Specifically we should reference the IANA Special-Purpose Address
Registries, which Boulder / Let's Encrypt use to ensure we don't contact
internal addresses during validation:

https://www.iana.org/assignments/iana-ipv4-special-registry/iana-ipv4-special-registry.xhtml
https://www.iana.org/assignments/iana-ipv6-special-registry/iana-ipv6-special-registry.xhtml

> However, if someone wanted to use ACME for a private intranet CA,
> correct firewalling like that is much harder.
>
This is a good point. Perhaps the guidance should be that an intranet CA
that chooses to allow validation of special-purpose addresses should not
allow requests from untrusted zones.
>
> The spec could also discourage including the HTTP body in an
> Unauthorized error's detail field.
>
This is a tradeoff. For the public CA case, I think it is useful to be
able to inform users what was received instead of the expected token,
since it can help them debug the problem.

---

From: Richard Barnes <[email-masked]>
Date: Mon, 13 Jun 2016 13:22:36 +0200

Hey Blake,

Thanks for bringing this up.  I agree that this would be good to document
in the Security Considerations, or maybe within the Operational
Considerations below. Would you like to take a shot at a PR?

Thanks,
--Richard

On Thu, Jun 9, 2016 at 8:30 PM, Blake Burkhart <[email-masked]> wrote:

> connections to internal network addresses. However, if someone wanted to
> use ACME for a private intranet CA, correct firewalling like that is much
> harder. The spec could also discourage including the HTTP body in an
> Unauthorized error's detail field. Or at least don't include the HTTP body
> if a redirect was followed.
>
> (I reported this privately [email-masked] before creating
> this GitHub issue. This is not an issue for Let's Encrypt.)
>
> --
> Blake
>
> _______________________________________________
> Acme mailing list
> [email-masked]
> https://www.ietf.org/mailman/listinfo/acme
>
>

---

From: Blake Burkhart <[email-masked]>
Date: Mon, 13 Jun 2016 15:49:30 -0500

On Mon, Jun 13, 2016 at 6:22 AM, Richard Barnes <[email-masked]> wrote:
> Thanks for bringing this up.  I agree that this would be good to document in
> the Security Considerations, or maybe within the Operational Considerations
> below. Would you like to take a shot at a PR?

I'll let someone else do it I think, not quite sure how to write it
myself. I think I agree with all of Jacob's comments. The spec can
probably just suggest to not perform any HTTP requests to
Special-Purpose Addresses while following HTTP redirects, unless
specifically configured otherwise (such as for an intranet CA).

I also realized that you can get similar behavior without using
redirects by setting the A record of a domain to point to an internal
IP address (though of course you can't control the HTTP path this
way). I can't actually see how it would be of any use to an attacker,
but it's possible. Making sure the filtering is done at the IP
address/network level will fix both. That is, implementations
shouldn't fix this only while following redirects, it should be done
for all HTTP requests.

-- 
Blake