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

Be more careful about environment variables #29

Closed
thejh opened this issue Mar 10, 2013 · 5 comments
Closed

Be more careful about environment variables #29

thejh opened this issue Mar 10, 2013 · 5 comments

Comments

@thejh
Copy link

thejh commented Mar 10, 2013

As far as I can see, login_duo doesn't clear environment variables before performing HTTPS requests. Have a look at these things in lib/https.c:

    if (!RAND_status()) {
            if ((p = getenv("RANDFILE")) != NULL) {
                    RAND_load_file(p, 8192);
            } else {
                    ctx->errstr = "No /dev/random, EGD, or $RANDFILE";
                    return (HTTPS_ERR_LIB);
            }
    }

and

    if ((p = getenv("http_proxy")) != NULL) {
            if (strstr(p, "://") != NULL) {
                    if (strncmp(p, "http://", 7) != 0) {
                            ctx->errstr = "http_proxy must be HTTP";
                            return (HTTPS_ERR_CLIENT);
                    }
                    p += 7;
            }
            p = strdup(p);

            if ((ctx->proxy = strchr(p, '@')) != NULL) {
                    *ctx->proxy++ = '\0';
                    ctx->proxy_auth = p;
            } else {
                    ctx->proxy = p;
            }
            strtok(ctx->proxy, "/");

            if ((ctx->proxy_port = strchr(ctx->proxy, ':')) != NULL) {
                    *ctx->proxy_port++ = '\0';
            } else {
                    ctx->proxy_port = "80";
            }
    }

This means that on systems without /dev/urandom, every user can cause duo_unix to read files in the context of the duo helper user and to then send data derived from these files to a user-specified host.

@jonoberheide
Copy link

For the RANDFILE env var, the login_duo process drops privileges to the sshd privsep user before calling https_init, which is where the getenv and RAND_load_file takes place. Therefore, only files readable by the sshd privsep user could be provided via RANDFILE, which limits the target set of files to only world-readable files on any sane system. And of course, world-readable files are already readable by the user executing the login_duo command.

So, an affected system would need to lack a sufficient entropy source to cause RAND_status to fail, there would need to be a sensitive file owned by the privsep user, and you would need some way to derive the data from that file loaded via RAND_load_file. If you can think of any interesting scenarios where it might be feasible (particularly for the latter two conditions), let me know!

As for the HTTP_PROXY env var, the HTTP proxy support is limited to simple CONNECT-based proxying. Therefore, you wouldn't be able to MITM the connection to snoop on any data (not that there's much useful data in the request that you wouldn't already have access to with your own user's invocation of login_duo). A custom CA cert can be specified in the configuration file, but if you cannot specify your own configuration file with -c if the setuid bit is present on the login_duo binary.

@thejh
Copy link
Author

thejh commented Mar 22, 2013

For the RANDFILE env var, the login_duo process drops privileges to the sshd privsep user before calling https_init, which is where the getenv and RAND_load_file takes place. Therefore, only files readable by the sshd privsep user could be provided via RANDFILE, which limits the target set of files to only world-readable files on any sane system.

Isn't the duo configuration file with the API secrets readable for that user, too? That's what it looks like on my PC (but maybe I just misconfigured Duo):

-rw------- 1 sshd root 231 Mär 10 19:33 /etc/duo/login_duo.conf

So, an affected system would need to lack a sufficient entropy source to cause RAND_status to fail

Some applications do a chroot() into an empty, non-user-writable directory or so in order to mitigate
attacks. I believe that Google's Chromium browser even includes a setuid helper for "sandboxing" some of the
browser's processes. So, if you can trick such a helper into chroot'ing an evil program (I think it has no protections against that) and then somehow get hold of a file descriptor to the real / (e.g. through a unix domain socket), you can execve() setuid processes and they will be inside the chroot. Well, I guess that this would fail unless the duo helper is compiled statically because all the shared libraries are missing, but it might happen.

and you would need some way to derive the data from that file loaded via RAND_load_file
[...]
As for the HTTP_PROXY env var, the HTTP proxy support is limited to simple CONNECT-based proxying. Therefore, you wouldn't be able to MITM the connection to snoop on any data (not that there's much useful data in the request that you wouldn't already have access to with your own user's invocation of login_duo).

I'm not sure about this, but if you have managed to make the contents of a secret file the source of randomness for crypto, maybe you can intercept the connection using the HTTP_PROXY var and derive the secret file's contents from the encryption key of the connection? If the amount of unknown data in the secret file was small enough, you might be able to get the key using brute force...

@thejh
Copy link
Author

thejh commented Mar 23, 2013

So, an affected system would need to lack a sufficient entropy source to cause RAND_status to fail

Some applications do a chroot() into an empty, non-user-writable directory or so in order to mitigate
attacks. [...] So, if you can trick such a helper into chroot'ing an evil program (I think it has no protections against that) and then somehow get hold of a file descriptor to the real / (e.g. through a unix domain socket), you can execve() setuid processes and they will be inside the chroot. Well, I guess that this would fail unless the duo helper is compiled statically because all the shared libraries are missing, but it might happen.

Oops, don't mind this one. Of course, the duo config file wouldn't be present in the chroot either, so the helper would probably just fail.

@jonoberheide
Copy link

Isn't the duo configuration file with the API secrets readable for that user, too?

Ah, of course, you're correct about the config file permissions. :-)

I'm not sure about this, but if you have managed to make the contents of a secret file the source of randomness for crypto, maybe you can intercept the connection using the HTTP_PROXY var and derive the secret file's contents from the encryption key of the connection? If the amount of unknown data in the secret file was small enough, you might be able to get the key using brute force...

I was thinking along the same lines with the brute force method. I haven't dug into the RAND_* internals to see how it's treating the RANDFILE entropy source, but I imagine there's some determinism there and could be brute forced if the secret data was constrained in size or format.

Let's consider the login_duo.conf file as a real-world example, since it's readable by the privsep user. Let's assume that the target login_duo.conf follows the default format/layout/spacing. Let's also assume that the config file only contains the default parameters of ikey/skey/hostname. Additionally, let's assume that the attacker knows the ikey and the hostname. That may not be true in most scenarios, but the ikey/hostname are not meant to be secret, so let's just assume they're available somehow to the attacker. So, the only unknown data would be skey. If a bruteforce vector is at all feasible there, the attacker would need to guess the skey, which is 40 characters of upper/lower alpha and digits and comes out to about 238 bits of entropy. We're entering infeasibility territory now... :-P

All that said, even if the attack was successful somehow, extracting the skey doesn't provide any value to the attacker. ;-) The attacker could use it to make authentication requests to the server (eg. initiate push notifications, etc) to cause annoyance to legit users, but there's no security impact.

@AaronAtDuo
Copy link
Contributor

Closing out this old issue

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

No branches or pull requests

3 participants