diff --git a/ChangeLog.txt b/ChangeLog.txt index f708d66c..eb4f9889 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -1,6 +1,15 @@ 1.4.12 - 201703xx ================= +Security: +- Fix CVE-2017-7650, which allows clients with username or client id set to + '#' or '+' to bypass pattern based ACLs or third party plugins. The fix + denies message sending or receiving of messages for clients with a '#' or + '+' in their username or client id and if the message is subject to a + pattern ACL check or plugin check. + Patches for other versions are available at + https://mosquitto.org/files/cve/2017-7650/ + Broker: - Fix mosquitto.db from becoming corrupted due to client messages being persisted with no stored message. Closes #424. @@ -11,6 +20,7 @@ Broker: - Fixes to readme.md. - Fix deprecation warning for OpenSSL 1.1. PR #416. - Don't segfault on duplicate bridge names. Closes #446. +- Fix CVE-2017-7650. 1.4.11 - 20170220 diff --git a/src/security.c b/src/security.c index 6ae9fb9c..d0c376bd 100644 --- a/src/security.c +++ b/src/security.c @@ -233,6 +233,21 @@ int mosquitto_acl_check(struct mosquitto_db *db, struct mosquitto *context, cons { username = context->username; } + + /* Check whether the client id or username contains a +, # or / and if + * so deny access. + * + * Do this check for every message regardless, we have to protect the + * plugins against possible pattern based attacks. + */ + if(username && strpbrk(username, "+#/")){ + _mosquitto_log_printf(NULL, MOSQ_LOG_NOTICE, "ACL denying access to client with dangerous username \"%s\"", username); + return MOSQ_ERR_ACL_DENIED; + } + if(context->id && strpbrk(context->id, "+#/")){ + _mosquitto_log_printf(NULL, MOSQ_LOG_NOTICE, "ACL denying access to client with dangerous client id \"%s\"", context->id); + return MOSQ_ERR_ACL_DENIED; + } return db->auth_plugin.acl_check(db->auth_plugin.user_data, context->id, username, topic, access); } } diff --git a/src/security_default.c b/src/security_default.c index 64ca846b..a41c21f4 100644 --- a/src/security_default.c +++ b/src/security_default.c @@ -261,6 +261,26 @@ int mosquitto_acl_check_default(struct mosquitto_db *db, struct mosquitto *conte } acl_root = db->acl_patterns; + + if(acl_root){ + /* We are using pattern based acls. Check whether the username or + * client id contains a +, # or / and if so deny access. + * + * Without this, a malicious client may configure its username/client + * id to bypass ACL checks (or have a username/client id that cannot + * publish or receive messages to its own place in the hierarchy). + */ + if(context->username && strpbrk(context->username, "+#/")){ + _mosquitto_log_printf(NULL, MOSQ_LOG_NOTICE, "ACL denying access to client with dangerous username \"%s\"", context->username); + return MOSQ_ERR_ACL_DENIED; + } + + if(context->id && strpbrk(context->id, "+#/")){ + _mosquitto_log_printf(NULL, MOSQ_LOG_NOTICE, "ACL denying access to client with dangerous client id \"%s\"", context->id); + return MOSQ_ERR_ACL_DENIED; + } + } + /* Loop through all pattern ACLs. */ clen = strlen(context->id); while(acl_root){