]> git.immae.eu Git - github/shaarli/Shaarli.git/commitdiff
Corrected vulnerabilities (see report below)
authorSebastien SAUVAGE <sebsauvage@sebsauvage.net>
Sun, 3 Mar 2013 21:15:38 +0000 (22:15 +0100)
committerSebastien SAUVAGE <sebsauvage@sebsauvage.net>
Sun, 3 Mar 2013 21:15:38 +0000 (22:15 +0100)
Title : Shaarli Vulnerabilities
Author : @erwan_lr | @_WPScan_

Vendor : http://sebsauvage.net/wiki/doku.php?id=php:shaarli
Download : https://github.com/sebsauvage/Shaarli/archive/master.zip |
http://sebsauvage.net/files/shaarli_0.0.40beta.zip
Affected versions : master-705F835, 0.0.40-beta (versions below may also
be vulnerable)

Vulnerabilities : Persistent XSS & Unvalidated Redirects and Forwards

Persistent XSS :
- During the instalation or configuration modification, the title field
is vulnerable. e.g <script>alert(1)</script>
Quotes can not be used because of var_export(), but String.fromCharCode
works

- The url field of a link is vulnerable :

When there is no redirector : javascript:alert(1)
Then, the code is triggered when a user click the url of a link

Or with a classic XSS : "><script>alert(1)</script>

Unvalidated Redirects and Forwards :
A request with the param linksperpage or privateonly can be used to
redirect a user to an arbitrary referer

e.g
GET /Audit/Shaarli/master-705f835/?linksperpage=10 HTTP/1.1
Host: 127.0.0.1
Referer: https://duckduckgo.com

History :
March 2, 2013
- Vendor contacted

index.php
tpl/linklist.html
tpl/page.header.html

index bac5b7d272bb32d0c8ede066f4fd0884400d05b2..224690efeeb97f88e6721e9dec58ae68ab5d4926 100644 (file)
--- a/index.php
+++ b/index.php
@@ -1265,7 +1265,11 @@ function renderPage()
     if (isset($_GET['linksperpage']))
     {
         if (is_numeric($_GET['linksperpage'])) { $_SESSION['LINKS_PER_PAGE']=abs(intval($_GET['linksperpage'])); }
-        header('Location: '.(empty($_SERVER['HTTP_REFERER'])?'?':$_SERVER['HTTP_REFERER']));
+        // Make sure the referer is from Shaarli itself.
+        $referer = '?';
+        if (!empty($_SERVER['HTTP_REFERER']) && strcmp(parse_url($_SERVER['HTTP_REFERER'],PHP_URL_HOST),$_SERVER['SERVER_NAME'])==0)
+            $referer = $_SERVER['HTTP_REFERER'];
+        header('Location: '.$referer);
         exit;
     }
     
@@ -1280,7 +1284,11 @@ function renderPage()
         {
             unset($_SESSION['privateonly']); // See all links
         }
-        header('Location: '.(empty($_SERVER['HTTP_REFERER'])?'?':$_SERVER['HTTP_REFERER']));
+        // Make sure the referer is from Shaarli itself.
+        $referer = '?';
+        if (!empty($_SERVER['HTTP_REFERER']) && strcmp(parse_url($_SERVER['HTTP_REFERER'],PHP_URL_HOST),$_SERVER['SERVER_NAME'])==0)
+            $referer = $_SERVER['HTTP_REFERER'];
+        header('Location: '.$referer);
         exit;
     }
 
@@ -1437,7 +1445,10 @@ function renderPage()
         if (!tokenOk($_POST['token'])) die('Wrong token.'); // Go away !
         $tags = trim(preg_replace('/\s\s+/',' ', $_POST['lf_tags'])); // Remove multiple spaces.
         $linkdate=$_POST['lf_linkdate'];
-        $link = array('title'=>trim($_POST['lf_title']),'url'=>trim($_POST['lf_url']),'description'=>trim($_POST['lf_description']),'private'=>(isset($_POST['lf_private']) ? 1 : 0),
+        $url = trim($_POST['lf_url']);
+        if (!startsWith($url,'http:') && !startsWith($url,'ftp:') && !startsWith($url,'magnet:') && !startsWith($url,'?'))
+            $url = 'http://'.$url;
+        $link = array('title'=>trim($_POST['lf_title']),'url'=>$url,'description'=>trim($_POST['lf_description']),'private'=>(isset($_POST['lf_private']) ? 1 : 0),
                       'linkdate'=>$linkdate,'tags'=>str_replace(',',' ',$tags));
         if ($link['title']=='') $link['title']=$link['url']; // If title is empty, use the URL as title.
         $LINKSDB[$linkdate] = $link;
index 3a703512d32b0ca49af369a7f91923ebcd7f759e..37ffeb6465f4f4db42bc3710bf910096f38b1768 100644 (file)
@@ -40,7 +40,7 @@
                         <input type="hidden" name="token" value="{$token}"><input type="hidden" name="delete_link"><input type="image" alt="Delete" src="images/delete_icon.png#" title="Delete" class="button_delete" onClick="return confirmDeleteLink();"></form>
                     </div>
                 {/if}
-                <span class="linktitle"><a href="{$redirector}{$value.url}">{$value.title|htmlspecialchars}</a></span>
+                <span class="linktitle"><a href="{$redirector}{$value.url|htmlspecialchars}">{$value.title|htmlspecialchars}</a></span>
                 <br>
                 {if="$value.description"}<div class="linkdescription"{if condition="$search_type=='permalink'"} style="max-height:none !important;"{/if}>{$value.description}</div>{/if}
                 {if="!$GLOBALS['config']['HIDE_TIMESTAMPS'] || isLoggedIn()"}
index 60fc176769bd46e688c3d6e2c5c414bc43254455..125b365b12e4bb9a7d0c56fe6535e98c5caa61b5 100644 (file)
@@ -2,7 +2,7 @@
     <div id="logo" title="Share your links !" onclick="document.location='?';"></div>
     <div style="float:right; font-style:italic; color:#bbb; text-align:right; padding:0 5 0 0;" class="nomobile">Shaare your links...<br>
         {if="!empty($linkcount)"}{$linkcount} links{/if}</div>
-    <span id="shaarli_title"><a href="?">{$shaarlititle}</a></span>
+    <span id="shaarli_title"><a href="?">{$shaarlititle|htmlspecialchars}</a></span>
   
 {if="!empty($_GET['source']) && $_GET['source']=='bookmarklet'"}
     {ignore} When called as a popup from bookmarklet, do not display menu. {/ignore}