From a06aa79a308585cc6048f725f2dc3c1d55ff9991 Mon Sep 17 00:00:00 2001 From: Alexey Sokolov Date: Wed, 12 Jun 2019 08:57:29 +0100 Subject: [PATCH] Fix remote code execution and privilege escalation vulnerability. To trigger this, need to have a user already. Thanks for Jeriko One for finding and reporting this. CVE-2019-12816 --- include/znc/Modules.h | 1 + src/Modules.cpp | 33 ++++++++++++++++++++++++++++----- 2 files changed, 29 insertions(+), 5 deletions(-) --- a/include/znc/Modules.h +++ b/include/znc/Modules.h @@ -1253,6 +1253,7 @@ public: private: static ModHandle OpenModule(const CString& sModule, const CString& sModPath, bool &bVersionMismatch, CModInfo& Info, CString& sRetMsg); + static bool ValidateModuleName(const CString& sModule, CString& sRetMsg); protected: CUser* m_pUser; --- a/src/Modules.cpp +++ b/src/Modules.cpp @@ -1014,9 +1014,26 @@ CModule* CModules::FindModule(const CStr return NULL; } +bool CModules::ValidateModuleName(const CString& sModule, CString& sRetMsg) { + for (unsigned int a = 0; a < sModule.length(); a++) { + if (((sModule[a] < '0') || (sModule[a] > '9')) && + ((sModule[a] < 'a') || (sModule[a] > 'z')) && + ((sModule[a] < 'A') || (sModule[a] > 'Z')) && (sModule[a] != '_')) { + sRetMsg = "Module names can only contain letters, numbers and underscores, [" + sModule + "] is invalid."; + return false; + } + } + + return true; +} + bool CModules::LoadModule(const CString& sModule, const CString& sArgs, CModInfo::EModuleType eType, CUser* pUser, CIRCNetwork *pNetwork, CString& sRetMsg) { sRetMsg = ""; + if (!ValidateModuleName(sModule, sRetMsg)) { + return false; + } + if (FindModule(sModule) != NULL) { sRetMsg = "Module [" + sModule + "] already loaded."; return false; @@ -1167,6 +1184,10 @@ bool CModules::ReloadModule(const CStrin bool CModules::GetModInfo(CModInfo& ModInfo, const CString& sModule, CString& sRetMsg) { CString sModPath, sTmp; + if (!ValidateModuleName(sModule, sRetMsg)) { + return false; + } + bool bSuccess; bool bHandled = false; GLOBALMODULECALL(OnGetModInfo(ModInfo, sModule, bSuccess, sRetMsg), &bHandled); @@ -1183,6 +1204,10 @@ bool CModules::GetModInfo(CModInfo& ModI bool CModules::GetModPathInfo(CModInfo& ModInfo, const CString& sModule, const CString& sModPath, CString& sRetMsg) { bool bVersionMismatch; + if (!ValidateModuleName(sModule, sRetMsg)) { + return false; + } + ModHandle p = OpenModule(sModule, sModPath, bVersionMismatch, ModInfo, sRetMsg); if (!p) @@ -1302,11 +1327,9 @@ ModHandle CModules::OpenModule(const CSt bVersionMismatch = false; sRetMsg.clear(); - for (unsigned int a = 0; a < sModule.length(); a++) { - if (((sModule[a] < '0') || (sModule[a] > '9')) && ((sModule[a] < 'a') || (sModule[a] > 'z')) && ((sModule[a] < 'A') || (sModule[a] > 'Z')) && (sModule[a] != '_')) { - sRetMsg = "Module names can only contain letters, numbers and underscores, [" + sModule + "] is invalid."; - return NULL; - } + + if (!ValidateModuleName(sModule, sRetMsg)) { + return NULL; } // The second argument to dlopen() has a long history. It seems clear