Back in March 2015, I reported a security issue in Yubiserver, a small specialized HTTP server to verify HOTP/OATH tokens generated by Yubico’s Yubikeys. I’m publishing the details for reference.
I was looking for a new Yubikey validation server and, given its small size, decided to code review any candidates due to their small size. While looking at yubiserve, I found security issues in the code.
CVE-2015-0842
CVE-2015-0842 is an SQL injection issue. Yubiserver’s database backend is SQLite. User input is not added to prepared statements using sqlite3_bind_text
, but instead uses sprintf(3)
without any escaping. This affects the first 12 bytes of a Yubico OTP in OTP mode in modhex encoding (although the encoding will be skipped if non-modhex characters are encountered). Because the attacker is limited to 12 characters inside the WHERE
clause of SELECT
query the attack potential is small.
A similar issue affects the id
parameter that is used to select a key for the HMAC that protects the response, with the exception that only a length restriction on the whole request exists. Again, this injection happens in a SELECT
query. While an attacker can escape the quoting and add arbitrary SQL in the WHERE
clause, the possibilities for exploitation are limited: INSERT
and DELETE
statements cannot be used in subqueries and separating an additional query using a semicolon does not work due to the use of sqlite3_prepare_v2
and sqlite3_step
over sqlite3_exec
.
The vulnerability can possibly be used to extract secret keys from the database using subqueries. This may be limited by the length limit on queries that can be executed. A proof of concept that tells us whether a secret key of a yubikey starts with “ab” would be:
curl \
$'http://localhost:port/wsapi/2.0/verify?otp=a&id=1\'\tAND\t(SELECT\taeskey\tFROM\tyubikeys)\tLIKE\t"ab%";--'
Links
CVE-2015-0843
CVE-2015-0843 covers multiple buffer overflows due to extensive use of sprintf(3)
without range checks. All inputs that end up in queries, log messages or are sent back in the response are affected.
Denial of service is trivial by sending long inputs:
curl \
"http://localhost:port/wsapi/2.0/verify?otp=x&id=$(openssl rand -hex 512)"
On most Linux distributions, this triggers the stack canary and kills the process. Further exploitation may be possible, but has not been attempted.
Links
Timeline
- 2015-03-31: Issue reported to the Debian security team, who agree to forward it upstream.
- 2015-05-28: Debian security team confirms they are still waiting for patches and agree to follow-up upstream.
- 2015-05-29: Upstream releases 0.6 with patches for the vulnerabilities.
- 2015-10-02: Debian security team confirms CVE-2015-0842 and CVE-2015-0843 are assigned to these issues and patches have not been backported to wheezy and jessie.
- 2017-02-13: Public release.
Mitigations
Updating to 0.6 fixes both vulnerabilities. The SQL injections no longer occur because the code uses prepared statements and parameter binding. The buffer overflows have been mitigated by switching to snprintf(3)
and providing appropriate sizes, truncating the data if it would overflow the buffer.
The update to 0.6 does not include functional changes, so upgrading should be safe.
Recommendations
Switch to a server implementation that does not suffer from buffer overflows by language design. For example:
- yubikey-server in Go
- yubikeyedup in Python