XWiki Platform Old Core vulnerable to Authentication Bypass Using the Login Action
Description
XWiki Platform Old Core is a core package for XWiki Platform, a generic wiki platform. Prior to versions 14.2 and 13.10.4, all rights checks that would normally prevent a user from viewing a document on a wiki can be bypassed using the login action and directly specified templates. This exposes title, content and comments of any document and properties of objects, though class and property name must be known. This is also exploitable on private wikis. This has been patched in versions 14.2 and 13.10.4 by properly checking view rights before loading documents and disallowing non-default templates in the login, registration and skin action. As a workaround, it would be possible to protect all templates individually by adding code to check access rights first.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
org.xwiki.platform:xwiki-platform-oldcoreMaven | < 13.10.4 | 13.10.4 |
org.xwiki.platform:xwiki-platform-oldcoreMaven | >= 14.0, < 14.2 | 14.2 |
Affected products
1- Range: < 13.10.4
Patches
29b7057d57a94XWIKI-19549: Disallow template override for login, register and skin
1 file changed · +9 −3
xwiki-platform-core/xwiki-platform-oldcore/src/main/java/com/xpn/xwiki/web/RegisterAction.java+9 −3 modified@@ -19,6 +19,9 @@ */ package com.xpn.xwiki.web; +import java.util.Arrays; +import java.util.List; + import javax.inject.Named; import javax.inject.Singleton; import javax.script.ScriptContext; @@ -55,17 +58,20 @@ public class RegisterAction extends XWikiAction /** Space where the registration config and class are stored. */ private static final String WIKI_SPACE = "XWiki"; + /** Allowed templates for this action. */ + private static final List<String> ALLOWED_TEMPLATES = Arrays.asList(REGISTER, "registerinline"); + @Override public boolean action(XWikiContext context) throws XWikiException { XWiki xwiki = context.getWiki(); XWikiRequest request = context.getRequest(); XWikiResponse response = context.getResponse(); - // Disallow template override with xpage parameter. - if (!REGISTER.equals(Utils.getPage(context.getRequest(), REGISTER))) { + // Limit template overrides with xpage to allowed templates. + if (!ALLOWED_TEMPLATES.contains(Utils.getPage(context.getRequest(), REGISTER))) { throw new XWikiException(XWikiException.MODULE_XWIKI, XWikiException.ERROR_XWIKI_ACCESS_DENIED, - String.format("Template may not be overriden with 'xpage' in [%s] action.", REGISTER)); + String.format("Forbidden template override with 'xpage' in [%s] action.", REGISTER)); } String register = request.getParameter(REGISTER);
71a6d0bb6f8aXWIKI-19549: Disallow template override for login, register and skin
6 files changed · +99 −26
xwiki-platform-core/xwiki-platform-oldcore/src/main/java/com/xpn/xwiki/web/LoginAction.java+15 −1 modified@@ -37,6 +37,8 @@ @Singleton public class LoginAction extends XWikiAction { + private static final String LOGIN = "login"; + /** * Default constructor. */ @@ -45,6 +47,18 @@ public LoginAction() this.waitForXWikiInitialization = false; } + @Override + public boolean action(XWikiContext context) throws XWikiException + { + // Disallow template override with xpage parameter. + if (!LOGIN.equals(Utils.getPage(context.getRequest(), LOGIN))) { + throw new XWikiException(XWikiException.MODULE_XWIKI, XWikiException.ERROR_XWIKI_ACCESS_DENIED, + String.format("Template may not be overriden with 'xpage' in [%s] action.", LOGIN)); + } + + return super.action(context); + } + @Override public String render(XWikiContext context) throws XWikiException { @@ -53,6 +67,6 @@ public String render(XWikiContext context) throws XWikiException if (!"1".equals(context.getRequest().getParameter("loginLink"))) { context.getResponse().setStatus(401); } - return "login"; + return LOGIN; } }
xwiki-platform-core/xwiki-platform-oldcore/src/main/java/com/xpn/xwiki/web/LoginErrorAction.java+15 −1 modified@@ -37,9 +37,23 @@ @Singleton public class LoginErrorAction extends XWikiAction { + private static final String LOGIN = "login"; + + @Override + public boolean action(XWikiContext context) throws XWikiException + { + // Disallow template override with xpage parameter. + if (!LOGIN.equals(Utils.getPage(context.getRequest(), LOGIN))) { + throw new XWikiException(XWikiException.MODULE_XWIKI, XWikiException.ERROR_XWIKI_ACCESS_DENIED, + String.format("Template may not be overriden with 'xpage' in [%s] action.", LOGIN)); + } + + return super.action(context); + } + @Override public String render(XWikiContext context) throws XWikiException { - return "login"; + return LOGIN; } }
xwiki-platform-core/xwiki-platform-oldcore/src/main/java/com/xpn/xwiki/web/LoginSubmitAction.java+15 −1 modified@@ -42,13 +42,27 @@ @Singleton public class LoginSubmitAction extends XWikiAction { + private static final String LOGIN = "login"; + + @Override + public boolean action(XWikiContext context) throws XWikiException + { + // Disallow template override with xpage parameter. + if (!LOGIN.equals(Utils.getPage(context.getRequest(), LOGIN))) { + throw new XWikiException(XWikiException.MODULE_XWIKI, XWikiException.ERROR_XWIKI_ACCESS_DENIED, + String.format("Template may not be overriden with 'xpage' in [%s] action.", LOGIN)); + } + + return super.action(context); + } + @Override public String render(XWikiContext context) throws XWikiException { String msg = (String) context.get("message"); if (StringUtils.isNotBlank(msg)) { context.getResponse().setStatus(HttpServletResponse.SC_FORBIDDEN); } - return "login"; + return LOGIN; } }
xwiki-platform-core/xwiki-platform-oldcore/src/main/java/com/xpn/xwiki/web/RegisterAction.java+6 −0 modified@@ -62,6 +62,12 @@ public boolean action(XWikiContext context) throws XWikiException XWikiRequest request = context.getRequest(); XWikiResponse response = context.getResponse(); + // Disallow template override with xpage parameter. + if (!REGISTER.equals(Utils.getPage(context.getRequest(), REGISTER))) { + throw new XWikiException(XWikiException.MODULE_XWIKI, XWikiException.ERROR_XWIKI_ACCESS_DENIED, + String.format("Template may not be overriden with 'xpage' in [%s] action.", REGISTER)); + } + String register = request.getParameter(REGISTER); if (register != null && register.equals("1")) { // CSRF prevention
xwiki-platform-core/xwiki-platform-oldcore/src/main/java/com/xpn/xwiki/web/SkinAction.java+17 −2 modified@@ -66,6 +66,7 @@ @Singleton public class SkinAction extends XWikiAction { + /** Logging helper. */ private static final Logger LOGGER = LoggerFactory.getLogger(SkinAction.class); @@ -83,14 +84,28 @@ public class SkinAction extends XWikiAction */ private static final String ENCODING = "UTF-8"; + private static final String DOCDOESNOTEXIST = "docdoesnotexist"; + + @Override + public boolean action(XWikiContext context) throws XWikiException + { + // Disallow template override with xpage parameter. + if (!DOCDOESNOTEXIST.equals(Utils.getPage(context.getRequest(), DOCDOESNOTEXIST))) { + throw new XWikiException(XWikiException.MODULE_XWIKI, XWikiException.ERROR_XWIKI_ACCESS_DENIED, + "Template may not be overriden with 'xpage' in [skin] action."); + } + + return super.action(context); + } + @Override public String render(XWikiContext context) throws XWikiException { try { return render(context.getRequest().getPathInfo(), context); } catch (IOException e) { context.getResponse().setStatus(404); - return "docdoesnotexist"; + return DOCDOESNOTEXIST; } } @@ -177,7 +192,7 @@ public String render(String path, XWikiContext context) throws XWikiException, I } if (!found) { context.getResponse().setStatus(404); - return "docdoesnotexist"; + return DOCDOESNOTEXIST; } return null; }
xwiki-platform-core/xwiki-platform-oldcore/src/main/java/com/xpn/xwiki/XWiki.java+31 −21 modified@@ -5917,31 +5917,41 @@ && getRightService().hasAccessLevel("view", XWikiRightService.GUEST_USER_FULLNAM } } - context.put("doc", doc); - context.put("cdoc", doc); - vcontext.put("doc", doc.newDocument(context)); - vcontext.put("cdoc", vcontext.get("doc")); - XWikiDocument tdoc; - - // If the parameter language exists and is empty, it means we want to force loading the regular document - // not a translation. This should be handled later by doing a better separation between locale used in the UI - // and for loading the documents. - if ("".equals(context.getRequest().getParameter("language"))) { - tdoc = doc; + if (!"skin".equals(context.getAction()) && !this.getRightService().hasAccessLevel("view", + user.getFullName(), doc.getFullName(), context)) { + // If for some reason (e.g., login action) the user has rights for the action but no view right on the + // document, do not load the document into the context. + setPhonyDocument(reference, context, vcontext); + doc = context.getDoc(); + context.put("tdoc", doc); + context.put("cdoc", doc); } else { - tdoc = doc.getTranslatedDocument(context); - } + context.put("doc", doc); + context.put("cdoc", doc); + vcontext.put("doc", doc.newDocument(context)); + vcontext.put("cdoc", vcontext.get("doc")); + XWikiDocument tdoc; + + // If the parameter language exists and is empty, it means we want to force loading the regular document + // not a translation. This should be handled later by doing a better separation between locale used in the UI + // and for loading the documents. + if ("".equals(context.getRequest().getParameter("language"))) { + tdoc = doc; + } else { + tdoc = doc.getTranslatedDocument(context); + } - try { - String rev = (String) context.get("rev"); - if (StringUtils.isNotEmpty(rev)) { - tdoc = getDocument(tdoc, rev, context); + try { + String rev = (String) context.get("rev"); + if (StringUtils.isNotEmpty(rev)) { + tdoc = getDocument(tdoc, rev, context); + } + } catch (Exception ex) { + // Invalid version, just use the most recent one } - } catch (Exception ex) { - // Invalid version, just use the most recent one + context.put("tdoc", tdoc); + vcontext.put("tdoc", tdoc.newDocument(context)); } - context.put("tdoc", tdoc); - vcontext.put("tdoc", tdoc.newDocument(context)); return true; }
Vulnerability mechanics
Synthesis attempt was rejected by the grounding validator. Re-run pending.
References
7- github.com/advisories/GHSA-8h89-34w2-jpfmghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2022-36092ghsaADVISORY
- github.com/xwiki/xwiki-platform/commit/71a6d0bb6f8ab718fcfaae0e9b8c16c2d69cd4bbghsax_refsource_MISCWEB
- github.com/xwiki/xwiki-platform/commit/9b7057d57a941592d763992d4299456300918208ghsax_refsource_MISCWEB
- github.com/xwiki/xwiki-platform/security/advisories/GHSA-8h89-34w2-jpfmghsax_refsource_CONFIRMWEB
- jira.xwiki.org/browse/XWIKI-18602ghsax_refsource_MISCWEB
- jira.xwiki.org/browse/XWIKI-19549ghsax_refsource_MISCWEB
News mentions
0No linked articles in our index yet.