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
|