aboutsummaryrefslogtreecommitdiffstats
path: root/main/znc/CVE-2019-12816.patch
blob: 6d4d8b199d7375bceb4732ad8fcf78ee92f09a37 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
From 8de9e376ce531fe7f3c8b0aa4876d15b479b7311 Mon Sep 17 00:00:00 2001
From: Alexey Sokolov <alexey+znc@asokolov.org>
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 <jeriko.one@gmx.us> for finding and reporting this.

CVE-2019-12816
---
 include/znc/Modules.h |  1 +
 src/Modules.cpp       | 38 +++++++++++++++++++++++++++++---------
 2 files changed, 30 insertions(+), 9 deletions(-)

diff --git a/include/znc/Modules.h b/include/znc/Modules.h
index 28fdd3a62..db8f87b81 100644
--- a/include/znc/Modules.h
+++ b/include/znc/Modules.h
@@ -1600,6 +1600,7 @@ class CModules : public std::vector<CModule*>, private CCoreTranslationMixin {
   private:
     static ModHandle OpenModule(const CString& sModule, const CString& sModPath,
                                 CModInfo& Info, CString& sRetMsg);
+    static bool ValidateModuleName(const CString& sModule, CString& sRetMsg);
 
   protected:
     CUser* m_pUser;
diff --git a/src/Modules.cpp b/src/Modules.cpp
index 5aec7805a..d41951a8d 100644
--- a/src/Modules.cpp
+++ b/src/Modules.cpp
@@ -1624,11 +1624,30 @@ CModule* CModules::FindModule(const CString& sModule) const {
     return nullptr;
 }
 
+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 =
+                t_f("Module names can only contain letters, numbers and "
+                    "underscores, [{1}] is invalid")(sModule);
+            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) != nullptr) {
         sRetMsg = t_f("Module {1} already loaded.")(sModule);
         return false;
@@ -1781,6 +1800,10 @@ bool CModules::ReloadModule(const CString& sModule, const CString& sArgs,
 
 bool CModules::GetModInfo(CModInfo& ModInfo, const CString& sModule,
                           CString& sRetMsg) {
+    if (!ValidateModuleName(sModule, sRetMsg)) {
+        return false;
+    }
+
     CString sModPath, sTmp;
 
     bool bSuccess;
@@ -1799,6 +1822,10 @@ bool CModules::GetModInfo(CModInfo& ModInfo, const CString& sModule,
 
 bool CModules::GetModPathInfo(CModInfo& ModInfo, const CString& sModule,
                               const CString& sModPath, CString& sRetMsg) {
+    if (!ValidateModuleName(sModule, sRetMsg)) {
+        return false;
+    }
+
     ModInfo.SetName(sModule);
     ModInfo.SetPath(sModPath);
 
@@ -1911,15 +1938,8 @@ ModHandle CModules::OpenModule(const CString& sModule, const CString& sModPath,
     // Some sane defaults in case anything errors out below
     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 =
-                t_f("Module names can only contain letters, numbers and "
-                    "underscores, [{1}] is invalid")(sModule);
-            return nullptr;
-        }
+    if (!ValidateModuleName(sModule, sRetMsg)) {
+        return nullptr;
     }
 
     // The second argument to dlopen() has a long history. It seems clear