-1

I found an XSS vuln at a big wiki software. Here's the vuln code:

<?php
/**
 * Mock load.php with pre-defined test modules.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 * http://www.gnu.org/copyleft/gpl.html
 *
 * @file
 * @package MediaWiki
 * @author Lupo
 * @since 1.20
 */
header( 'Content-Type: text/javascript; charset=utf-8' );

$moduleImplementations = [
    'testUsesMissing' => "
mw.loader.implement( 'testUsesMissing', function () {
    mw.loader.testFail( 'Module usesMissing script should not run.' );
}, {}, {});
",

    'testUsesNestedMissing' => "
mw.loader.implement( 'testUsesNestedMissing', function () {
    mw.loader.testFail('Module testUsesNestedMissing script should not run.' );
}, {}, {});
",

    'testSkipped' => "
mw.loader.implement( 'testSkipped', function () {
    mw.loader.testFail( false, 'Module testSkipped was supposed to be skipped.' );
}, {}, {});
",

    'testNotSkipped' => "
mw.loader.implement( 'testNotSkipped', function () {}, {}, {});
",

    'testUsesSkippable' => "
mw.loader.implement( 'testUsesSkippable', function () {}, {}, {});
",

    'testUrlInc' => "
mw.loader.implement( 'testUrlInc', function () {} );
",
    'testUrlInc.a' => "
mw.loader.implement( 'testUrlInc.a', function () {} );
",
    'testUrlInc.b' => "
mw.loader.implement( 'testUrlInc.b', function () {} );
",
    'testUrlOrder' => "
mw.loader.implement( 'testUrlOrder', function () {} );
",
    'testUrlOrder.a' => "
mw.loader.implement( 'testUrlOrder.a', function () {} );
",
    'testUrlOrder.b' => "
mw.loader.implement( 'testUrlOrder.b', function () {} );
",
];

$response = '';

// Does not support the full behaviour of ResourceLoaderContext::expandModuleNames(),
// Only supports dotless module names joined by comma,
// with the exception of the hardcoded cases for testUrl*.
if ( isset( $_GET['modules'] ) ) {
    if ( $_GET['modules'] === 'testUrlInc,testUrlIncDump|testUrlInc.a,b' ) {
        $modules = [ 'testUrlInc', 'testUrlIncDump', 'testUrlInc.a', 'testUrlInc.b' ];
    } elseif ( $_GET['modules'] === 'testUrlOrder,testUrlOrderDump|testUrlOrder.a,b' ) {
        $modules = [ 'testUrlOrder', 'testUrlOrderDump', 'testUrlOrder.a', 'testUrlOrder.b' ];
    } else {
        $modules = explode( ',', $_GET['modules'] );
    }
    foreach ( $modules as $module ) {
        if ( isset( $moduleImplementations[$module] ) ) {
            $response .= $moduleImplementations[$module];
        } elseif ( preg_match( '/^test.*Dump$/', $module ) === 1 ) {
            $queryModules = $_GET['modules'];
            $queryVersion = isset( $_GET['version'] ) ? strval( $_GET['version'] ) : null;
            $response .= 'mw.loader.implement( ' . json_encode( $module )
                . ', function ( $, jQuery, require, module ) {'
                . 'module.exports.query = { '
                . 'modules: ' . json_encode( $queryModules ) . ','
                . 'version: ' . json_encode( $queryVersion )
                . ' };'
                . '} );';
        } else {
            // Default
            $response .= 'mw.loader.state(' . json_encode( $module ) . ', "missing" );' . "\n";
        }
    }
}

echo $response;

The output of $_GET["modules"] isnt filtered. Can you tell me if this XSS is vulnerable and also dangerous in your eyes?

schroeder
  • 123,438
  • 55
  • 284
  • 319
  • You've put a dump of code without any context - how is this used in the software, and what payload would result in a problem? Without those details, it's effectively asking for a code review. – Matthew Jul 19 '18 at 13:24
  • Thanks for your answer, i see ...in ie9 its working with url parameter ?modules=test.Dump&version=%3Cbody%20onload=alert(document.cookie);%3E ... but you are right - ill report it to the vendor - but thanks anyway! – Robert Beran Jul 19 '18 at 13:35
  • okay its working with ie 10 as well ... – Robert Beran Jul 19 '18 at 13:39
  • 3
    Two things: first, you just potentially outed a vuln on a major software package. Second, it's a unit test .... – schroeder Jul 19 '18 at 14:07
  • Seems XSS safe, but I wonder how this behaves if the `GET` parameter is an array (like `?modules[0]=&modules[1]=&modules[2]=...`) – Xenos Jul 19 '18 at 14:33
  • 1
    @schroeder The first point is important, but does it matter that it's a unit test? The file seems to be standalone, and if the tests are bundled into releases, then reflected XSS would be exploitable (if it exists). – tim Jul 19 '18 at 15:01
  • Hello together - i think this thread isnt good for everyone ... i dont want to make this public - i want to apologize for that - maybe u can close or delete this thread? Would be nice ... – Robert Beran Jul 20 '18 at 21:14

3 Answers3

5

This doesn't seem dangerous as the content type isn't HTML:

header( 'Content-Type: text/javascript; charset=utf-8' );

For specifics about XSS and content type text/javascript see eg Reflective XSS in script codes with Content Type “text/javascript”.

As an aside, I would suggest to either anonymize the code in the future or to not ask such a question in a public forum. Full disclosure without contacting the vendor first is bad form.

tim
  • 29,018
  • 7
  • 95
  • 119
  • IMO, Open source/GNU stuff is meant to be shared publicly so it's fine – Xenos Jul 19 '18 at 14:29
  • 4
    @Xenos No, it is **not** fine. The reason why you don't publish vulnerabilities in public before contacting the vendor / maintainer team is that doing so puts end-users in danger. Whether the software is open source or proprietary doesn't make a difference in this regard. Those in a position to fix a vulnerability need to be the first to learn about it so they get a head-start to work on a patch before the black hats start to exploit it. – Philipp Jul 19 '18 at 14:44
  • okay - i reported it yesterday to the vendor - and yes it is xss -> just try xenotix or something else to the ?modules=[X] and you will get the stuff! But i wont go deeper... to prevent the vendor from any damage ... – Robert Beran Jul 20 '18 at 08:49
  • @RobertBeran I don't see how it's XSS (just because a tool says so doesn't mean it really is). But if you remember, it would be great if you could update us here once the vendor has released a fix. – tim Jul 20 '18 at 09:23
  • @RobertBeran FYI, I tested with IE9, and it doesn't work. With content type `text/javascript`, IE9 offers me the file for download instead of executing the script. I also thought about the possibility to use this to bypass CSP policies (if there is an XSS issue somewhere), but that doesn't work either as they properly JSON encode the input. – tim Jul 20 '18 at 09:44
  • okay - one thing i can say try this in ie 10 or ie 9 : url/mediawiki-1.31.0/tests/qunit/data/load.mock.php?modules="> – Robert Beran Jul 20 '18 at 11:03
3

For reference, the file in question is https://github.com/wikimedia/mediawiki/blob/master/tests/qunit/data/load.mock.php

It's partially protected with a 'Deny from all' .htaccess in the root of the test directory https://github.com/wikimedia/mediawiki/blob/master/tests/.htaccess

Deny from all
schroeder
  • 123,438
  • 55
  • 284
  • 319
Sam Reed
  • 31
  • 3
  • on my installation - here: https://lists.wikimedia.org/pipermail/mediawiki-announce/2018-June/000221.html it isnt protected by any htaccess!!! – Robert Beran Jul 20 '18 at 15:58
  • 2
    Known packaging issue for the 1.30 tarball – Sam Reed Jul 20 '18 at 17:03
  • By default, Apache doesn't parse `htaccess` files (and other servers never do). If the application requires `AllowOverride All` to run, then this is a small mitigation. But if an XSS vulnerability exists in this file, it would still be a problem. – tim Jul 21 '18 at 07:21
0

If I read this code correctly it is listing the installed modules on the web server. This is a vulnerability but you'd have to be the server admin and have a module with a name like <script>alert('xss');</script> .

However is it an XSS? OWASP defines XSS as :

"Cross-Site Scripting (XSS) attacks are a type of injection, in which malicious scripts are injected into otherwise benign and trusted websites. XSS attacks occur when an attacker uses a web application to send malicious code, generally in the form of a browser side script, to a different end user. Flaws that allow these attacks to succeed are quite widespread and occur anywhere a web application uses input from a user within the output it generates without validating or encoding it." https://www.owasp.org/index.php/Cross-site_Scripting_(XSS)

Since this attack would be from an authenticated user on the operating system it would not be an XSS.

Joe M
  • 2,997
  • 1
  • 6
  • 13
  • The definition never mentions the "authenticated" status of the user. If you've injected javascript in a HTML document and it got interpreted by the browser, then it's a XSS. More generally, if you've injected something in a web document that got interpreted, then it's XSS. – Xenos Jul 20 '18 at 15:18
  • You wouldn't have to have server admin rights or a specific module. The module name comes from the URL (`$_GET['modules']`) and is echoed into the response (even if the module doesn't exist; in the `elseif` and `else` cases). But even *if* you would require both, it's still XSS (though not interesting if only server admins can enter the payload). – tim Jul 21 '18 at 07:26