CVE-2017-16613 (Python, published 2017-11-21T13:29Z)
Description: value: An issue was discovered in middleware.py in OpenStack Swauth through 1.2.0 when used with OpenStack Swift through 2.15.1. The Swift object store and proxy server are saving (unhashed) tokens retrieved from the Swauth middleware authentication mechanism to a log file as part of a GET URI. This allows attackers to bypass authentication by inserting a token into an X-Auth-Token header of a new request. NOTE: github.com/openstack/swauth URLs do not mean that Swauth is maintained by an official OpenStack project team.
Severity: HIGH (CVSS v3 base score: 9.8)
Weakness: CWE-287 \u2014 Improper Authentication
When an actor claims to have a given identity, the product does not prove or insufficiently proves that the claim is correct.
Repository: https://github.com/openstack/swauth
Files changed:
swauth/middleware.py
test/unit/test_authtypes.py
test/unit/test_middleware.py
Commit message: Hash token before storing it in Swift

Swauth uses token value as object name. Object names are logged in proxy
and object servers. Anybody with access to proxy/object server logs can
see token values. Attacker can use this token to access user's data in
Swift store. Instead of token, hashed token (with HASH_PATH_PREFIX and
HASH_PATH_SUFFIX) is used as object name now.

WARNING: In deployments without memcached this patch logs out all users
because tokens became invalid.

CVE-2017-16613

SecurityImpact
Closes-Bug: #1655781
Change-Id: I0d01e8e95400c82ef25f98e2d269532e83233c2c


Vulnerable code:
                             (self.auth_account, token[-1], token))
                (self.auth_account, candidate_token[-1], candidate_token))
                (self.auth_account, candidate_token[-1], candidate_token))
                         (self.auth_account, token[-1], token))
                         (self.auth_account, token[-1], token))

Fixed code:
from hashlib import sha512
from swift.common.utils import HASH_PATH_PREFIX
from swift.common.utils import HASH_PATH_SUFFIX
    def _get_concealed_token(self, token):
        """Returns hashed token to be used as object name in Swift.

        Tokens are stored in auth account but object names are visible in Swift
        logs. Object names are hashed from token.
        """
        enc_key = "%s:%s:%s" % (HASH_PATH_PREFIX, token, HASH_PATH_SUFFIX)
        return sha512(enc_key).hexdigest()

                object_name = self._get_concealed_token(token)
                             (self.auth_account, object_name[-1], object_name))
            object_name = self._get_concealed_token(candidate_token)
                (self.auth_account, object_name[-1], object_name))
            object_name = self._get_concealed_token(candidate_token)
                (self.auth_account, object_name[-1], object_name))
            object_name = self._get_concealed_token(token)
                         (self.auth_account, object_name[-1], object_name))
            object_name = self._get_concealed_token(token)
                         (self.auth_account, object_name[-1], object_name))

    def test_get_concealed_token(self):
        auth.HASH_PATH_PREFIX = 'start'
        auth.HASH_PATH_SUFFIX = 'end'
        token = 'token'

        # Check sha512 of "start:token:end"
        hashed_token = self.test_auth._get_concealed_token(token)
        self.assertEqual(hashed_token,
                'cb320540b0b4c69eb83de2ffb80714cb6766e2d06b5579d1a35a9c4c3fb62'
                '981ec50bcc3fb94521133e69a87d1efcb83efd78f35a06b6375e410201476'
                '0722f6')

        # Check sha512 of "start:token2:end"
        token = 'token2'
        hashed_token = self.test_auth._get_concealed_token(token)
        self.assertEqual(hashed_token,
                'ca400a6f884c168357f6af0609fda66aecd5aa613147167487495dd9f39fd'
                '8a77288568e65857294f01e398d7f14328e855f18517ccf94185d849e7f34'
                'f4259d')

        # Check sha512 of "start2:token2:end"
        auth.HASH_PATH_PREFIX = 'start2'
        hashed_token = self.test_auth._get_concealed_token(token)
        self.assertEqual(hashed_token,
                'ad594a69f44dd6e0aad54e360b01f15bd4833ccb4dcd9116d7aba0c25fb95'
                '670155b8cc7175def7aeeb4624a0f2bb7da5f0b204a4680ea7947d3d6a045'
                '22bdde')

        # Check sha512 of "start2:token2:end2"
        auth.HASH_PATH_SUFFIX = 'end2'
        hashed_token = self.test_auth._get_concealed_token(token)
        self.assertEqual(hashed_token,
                '446af2473ad6b28319a0fe02719a9d715b9941d12e0709851aedb4f53b890'
                '693e7f1328e68d870fe114f35f4ed9648b16a5013182db50d3d1f79a660f2'
                '0e078e')