From: Thomas Waldmann <tw@waldmann-edv.de>
Date: Mon, 26 Oct 2020 22:06:28 +0100
Subject: security: fix remote code execution via cache action, CVE-2020-25074
Origin: https://github.com/moinwiki/moin-1.9/commit/d1e5fc7d3708d877353ca64dd4aa7cfd1cde4cb4
Bug-Debian-Security: https://security-tracker.debian.org/tracker/CVE-2020-25074

An attacker with "write" permissions can upload specifically made
malicious code via the normal wiki attachment upload functionality and
later execute it on the server (as the same uid/gid as the wiki server
process) by using the vulnerable MoinMoin cache action.
---
 MoinMoin/action/cache.py | 27 ++++++++++++++++++++-------
 1 file changed, 20 insertions(+), 7 deletions(-)

diff --git a/MoinMoin/action/cache.py b/MoinMoin/action/cache.py
index a38967e8c761..f0bb23ee0a20 100644
--- a/MoinMoin/action/cache.py
+++ b/MoinMoin/action/cache.py
@@ -103,6 +103,19 @@ def key(request, wikiname=None, itemname=None, attachname=None, content=None, se
     return key
 
 
+def valid_key(key):
+    # make sure the key looks like keys generated by key()
+    if not isinstance(key, unicode):
+        # key is None (not given in url args) or something unexpected
+        return False
+    try:
+        int(key, 16)  # try to evaluate as hex number
+    except ValueError:
+        # was not a hex number
+        return False
+    return len(key) == 40  # hmac-sha1 hexdigest == 40 hex chars
+
+
 def put(request, key, data,
         filename=None,
         content_type=None,
@@ -234,14 +247,14 @@ def _do_remove(request, key):
     remove(request, key)
 
 
-def _do(request, do, key):
-    if do == 'get':
-        _do_get(request, key)
-    elif do == 'remove':
-        _do_remove(request, key)
-
 def execute(pagename, request):
     do = request.values.get('do')
     key = request.values.get('key')
-    _do(request, do, key)
+    valid = valid_key(key)  # validate untrusted input
+    if valid and do == 'get':
+        _do_get(request, key)
+    elif valid and do == 'remove':
+        _do_remove(request, key)
+    else:
+        request.status_code = 404
 
-- 
2.29.1

