[Discourse] RCE in AWS Simple Notification Service Webhook due to bad Certificate Validation Logic

Original Post:
Discourse SNS webhook RCE
We discussed this vulnerability during Episode 95 on 01 November 2021

Discourse exposes a webhook that takes a user-provided “subscribe URL” and passes it into open() unsanitized. Due to Discourse being written in Ruby, it’s possible to get command execution via the subscribe URL by way of the pipeline operator. However, the payload containing this URL is supposed to be signed by AWS, and a valid and verified certificate URL must be provided for the request to succeed.

Various checks are performed on the certificate URL, including verifying it’s HTTPS, and ensuring the URL pattern matches with the sns.*.amazonaws.com host. The path must also be a .pem extension. It’s possible that an attacker can reflect a fake certificate in an AWS page to bypass these checks and provide a seemingly valid signature. Further, because Ruby’s X509 certificate parser does loose parsing, it won’t reject a certificate with unrecognized data before and after the cert. So by getting a fake cert reflected in a page’s contents, these checks can be bypassed and a malicious payload can be signed.

Initially, they tried abusing the error page’s reflection of an invalid action to fake a cert. This wasn’t sufficient though, because an error page would serve a 400 error code, and the certificate request needed to receive a 200 OK. The final attack was to use the GetEndpointAttributes method, which allows you to pass a CustomUserData parameter that gets reflected in the page. This allows an attacker to bypass all the necessary checks and exploit the open() call to launch a reverse shell.