てきとうなメモ

本の感想とか技術メモとか

CVE-2016-6210の修正

OpenSSH 7.3がリリースされて、CVE-2016-6210が修正されたそうだ

sshd(8): Mitigate timing differences in password authentication

that could be used to discern valid from invalid account names
when long passwords were sent and particular password hashing
algorithms are in use on the server. CVE-2016-6210, reported by
EddieEzra.Harari at verint.com

http://www.openssh.com/txt/release-7.3

どう修正されたのかなと。gitリポジトリをcloneしてきてコミットログをみてみた。

$ git show 9286875a
commit 9286875a73b2de7736b5e50692739d314cd8d9dc
Author: Darren Tucker <[email protected]>
Date:   Fri Jul 15 13:32:45 2016 +1000

    Determine appropriate salt for invalid users.
    
    When sshd is processing a non-PAM login for a non-existent user it uses
    the string from the fakepw structure as the salt for crypt(3)ing the
    password supplied by the client.  That string has a Blowfish prefix, so on
    systems that don't understand that crypt will fail fast due to an invalid
    salt, and even on those that do it may have significantly different timing
    from the hash methods used for real accounts (eg sha512).  This allows
    user enumeration by, eg, sending large password strings.  This was noted
    by EddieEzra.Harari at verint.com (CVE-2016-6210).
    
    To mitigate, use the same hash algorithm that root uses for hashing
    passwords for users that do not exist on the system.  ok djm@

システム上のrootが使っているハッシュアルゴリズムと同じものを利用するようにしたと。なるほど。

openbsd-compat/xcrypt.cのpick_salt関数で/etc/shadowのrootのエントリから$id$salt$の部分を取得している。

/*
 * Pick an appropriate password encryption type and salt for the running
 * system.
 */
static const char *
pick_salt(void)
{
       struct passwd *pw;
       char *passwd, *p;
       size_t typelen;
       static char salt[32];

       if (salt[0] != '\0')
               return salt;
       strlcpy(salt, "xx", sizeof(salt));
       if ((pw = getpwuid(0)) == NULL)
               return salt;
       passwd = shadow_pw(pw);
       if (passwd[0] != '$' || (p = strrchr(passwd + 1, '$')) == NULL)
               return salt;  /* no $, DES */
       typelen = p - passwd + 1;
       strlcpy(salt, passwd, MIN(typelen, sizeof(salt)));
       explicit_bzero(passwd, strlen(passwd));
       return salt;
}

ただ、最新版のopenbsd-compat/xcrypt.cを見るとrootがパスワード持っているとは限らないので、初めて見つけたDES以外のエントリの$id$salt$を返すようになっていた。

/*
 * Pick an appropriate password encryption type and salt for the running
 * system by searching through accounts until we find one that has a valid
 * salt.  Usually this will be root unless the root account is locked out.
 * If we don't find one we return a traditional DES-based salt.
 */
static const char *
pick_salt(void)
{
        struct passwd *pw;
        char *passwd, *p; 
        size_t typelen;
        static char salt[32];

        if (salt[0] != '\0')
                return salt;
        strlcpy(salt, "xx", sizeof(salt));
        setpwent();
        while ((pw = getpwent()) != NULL) {
                passwd = shadow_pw(pw);
                if (passwd[0] == '$' && (p = strrchr(passwd+1, '$')) != NULL) {
                        typelen = p - passwd + 1;
                        strlcpy(salt, passwd, MIN(typelen, sizeof(salt)));
                        explicit_bzero(passwd, strlen(passwd));
                        goto out;
                }   
        }   
 out:
        endpwent();
        return salt;
}