From 7141742914cb1554809676d30911416bd2024cf9 Mon Sep 17 00:00:00 2001 From: Sam Reed Date: Mon, 28 Nov 2011 23:18:55 +0000 Subject: [PATCH] * (bug 32276) Skins were generating output using the internal page title which would allow anonymous users to determine wheter a page exists, potentially leaking private data. In fact, the curid and oldid request parameters would allow page titles to be enumerated even when they are not guessable. * (bug 32616) action=ajax requests were dispatched to the relevant internal functions without any read permission checks being done. This could lead to data leakage on private wikis. --- includes/AjaxDispatcher.php | 9 ++++++++- includes/OutputPage.php | 11 +++++++++-- includes/SkinTemplate.php | 18 +++++++++++++----- includes/Wiki.php | 16 +++++++++++++++- 4 files changed, 45 insertions(+), 9 deletions(-) diff --git a/includes/AjaxDispatcher.php b/includes/AjaxDispatcher.php index 17b154d61f..5bc9f06742 100644 --- a/includes/AjaxDispatcher.php +++ b/includes/AjaxDispatcher.php @@ -68,7 +68,7 @@ class AjaxDispatcher { * request. */ function performAction() { - global $wgAjaxExportList, $wgOut; + global $wgAjaxExportList, $wgOut, $wgUser; if ( empty( $this->mode ) ) { return; @@ -84,6 +84,13 @@ class AjaxDispatcher { 'Bad Request', "unknown function " . (string) $this->func_name ); + } elseif ( !in_array( 'read', User::getGroupPermissions( array( '*' ) ), true ) + && !$wgUser->isAllowed( 'read' ) ) + { + wfHttpError( + 403, + 'Forbidden', + 'You must log in to view pages.' ); } else { wfDebug( __METHOD__ . ' dispatching ' . $this->func_name . "\n" ); diff --git a/includes/OutputPage.php b/includes/OutputPage.php index 866275b9ff..e6b18a981f 100644 --- a/includes/OutputPage.php +++ b/includes/OutputPage.php @@ -2029,7 +2029,13 @@ class OutputPage extends ContextSource { || ( isset( $wgGroupPermissions['autoconfirmed'][$action] ) && $wgGroupPermissions['autoconfirmed'][$action] ) ) ) { $displayReturnto = null; - $returnto = $this->getTitle(); + + # Due to bug 32276, if a user does not have read permissions, + # $this->getTitle() will just give Special:Badtitle, which is + # not especially useful as a returnto parameter. Use the title + # from the request instead, if there was one. + $request = $this->getRequest(); + $returnto = Title::newFromURL( $request->getVal( 'title', '' ) ); if ( $action == 'edit' ) { $msg = 'whitelistedittext'; $displayReturnto = $returnto; @@ -2043,9 +2049,10 @@ class OutputPage extends ContextSource { } $query = array(); + if ( $returnto ) { $query['returnto'] = $returnto->getPrefixedText(); - $request = $this->getRequest(); + if ( !$request->wasPosted() ) { $returntoquery = $request->getValues(); unset( $returntoquery['title'] ); diff --git a/includes/SkinTemplate.php b/includes/SkinTemplate.php index c211e04d33..504c39392f 100644 --- a/includes/SkinTemplate.php +++ b/includes/SkinTemplate.php @@ -544,11 +544,19 @@ class SkinTemplate extends Skin { /* set up the default links for the personal toolbar */ $personal_urls = array(); - $page = $request->getVal( 'returnto', $this->thispage ); - $query = $request->getVal( 'returntoquery', $this->thisquery ); - $a = array( 'returnto' => $page ); - if( $query != '' ) { - $a['returntoquery'] = $query; + # Due to bug 32276, if a user does not have read permissions, + # $this->getTitle() will just give Special:Badtitle, which is + # not especially useful as a returnto parameter. Use the title + # from the request instead, if there was one. + $page = Title::newFromURL( $request->getVal( 'title', '' ) ); + $page = $request->getVal( 'returnto', $page ); + $a = array(); + if ( strval( $page ) !== '' ) { + $a['returnto'] = $page; + $query = $request->getVal( 'returntoquery', $this->thisquery ); + if( $query != '' ) { + $a['returntoquery'] = $query; + } } $returnto = wfArrayToCGI( $a ); if( $this->loggedin ) { diff --git a/includes/Wiki.php b/includes/Wiki.php index 4c2e92ac71..0a4c0eaf81 100644 --- a/includes/Wiki.php +++ b/includes/Wiki.php @@ -133,7 +133,7 @@ class MediaWiki { * @return void */ private function performRequest() { - global $wgServer, $wgUsePathInfo; + global $wgServer, $wgUsePathInfo, $wgTitle; wfProfileIn( __METHOD__ ); @@ -163,6 +163,20 @@ class MediaWiki { // We will check again in Article::view(). $permErrors = $title->getUserPermissionsErrors( 'read', $user ); if ( count( $permErrors ) ) { + // Bug 32276: allowing the skin to generate output with $wgTitle or + // $this->context->title set to the input title would allow anonymous users to + // determine whether a page exists, potentially leaking private data. In fact, the + // curid and oldid request parameters would allow page titles to be enumerated even + // when they are not guessable. So we reset the title to Special:Badtitle before the + // permissions error is displayed. + // + // The skin mostly uses $this->context->getTitle() these days, but some extensions + // still use $wgTitle. + + $badTitle = SpecialPage::getTitleFor( 'Badtitle' ); + $this->context->setTitle( $badTitle ); + $wgTitle = $badTitle; + wfProfileOut( __METHOD__ ); throw new PermissionsError( 'read', $permErrors ); } -- 2.20.1