diff -Nru cacti-0.8.8b+dfsg/debian/changelog cacti-0.8.8b+dfsg/debian/changelog
--- cacti-0.8.8b+dfsg/debian/changelog 2014-04-06 20:01:31.000000000 +0200
+++ cacti-0.8.8b+dfsg/debian/changelog 2015-06-27 21:31:29.000000000 +0200
@@ -1,3 +1,28 @@
+cacti (0.8.8b+dfsg-5ubuntu0.1) trusty-security; urgency=medium
+
+ * Security update (LP: #1210822):
+ - CVE-2015-2665 Cross-site scripting (XSS) vulnerability in Cacti
+ before 0.8.8d allows remote attackers to inject arbitrary web script
+ or HTML via unspecified vectors.
+ - CVE-2015-4342 SQL Injection and Location header injection from cdef
+ id
+ - CVE-2015-4454 SQL injection vulnerability in the
+ get_hash_graph_template function in lib/functions.php in Cacti before
+ 0.8.8d allows remote attackers to execute arbitrary SQL commands via
+ the graph_template_id parameter to graph_templates.php.
+ - Unassigned CVE SQL injection VN:JVN#78187936 / TN:JPCERT#98968540
+ - CVE-2014-5261 Unsufficient input sanitation leads to shell command
+ injection possibilities
+ - CVE-2014-5262 Incomplete and incorrect input parsing leads to SQL
+ injection attack scenarios
+ - CVE-2014-5025 Cross Site Scripting Vulnerability
+ - CVE-2014-5026 Cross Site Scripting Vulnerability
+ - CVE-2014-5043 Cross Site Scripting Vulnerability
+ - CVE-2014-2327 Cross Site Request Forgery Vulnerability
+ - CVE-2014-4002 Cross-Site Scripting Vulnerability
+
+ -- Paul Gevers Sat, 27 Jun 2015 14:25:12 +0200
+
cacti (0.8.8b+dfsg-5) unstable; urgency=high
* Fix postinst for lighttpd setups which fail on update due to
diff -Nru cacti-0.8.8b+dfsg/debian/patches/CVE-2014-2327_csrf.patch cacti-0.8.8b+dfsg/debian/patches/CVE-2014-2327_csrf.patch
--- cacti-0.8.8b+dfsg/debian/patches/CVE-2014-2327_csrf.patch 1970-01-01 01:00:00.000000000 +0100
+++ cacti-0.8.8b+dfsg/debian/patches/CVE-2014-2327_csrf.patch 2015-06-27 21:31:29.000000000 +0200
@@ -0,0 +1,649 @@
+Description: Until upstream rewrites every form to include such a thing
+ the mitigation to prevent CVE-2014-2327 is to add a token to each form
+ via javascript.
+ .
+ This patch and the idea is taken from:
+ http://forums.cacti.net/viewtopic.php?f=21&t=52335
+ .
+ The javascript code comes from http://repo.or.cz/w/csrf-magic.git or
+ http://csrf.htmlpurifier.org/ and is licensed under the BSD-2clause:
+ Copyright (c) 2008-2013, Edward Z. Yang
+ All rights reserved.
+ .
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+ .
+ Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ .
+ Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+ .
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ .
+ To prevent a php notice during installation of the cacti package Paul Gevers
+ added "!isset($_SERVER['REQUEST_METHOD']) || " to line 185 of csrf-magic.php.
+Source: http://forums.cacti.net/download/file.php?id=29231
+Reviewed-By: Paul Gevers
+
+--- /dev/null
++++ b/include/csrf/csrf-magic.js
+@@ -0,0 +1,186 @@
++/**
++ * @file
++ *
++ * Rewrites XMLHttpRequest to automatically send CSRF token with it. In theory
++ * plays nice with other JavaScript libraries, needs testing though.
++ */
++
++// Here are the basic overloaded method definitions
++// The wrapper must be set BEFORE onreadystatechange is written to, since
++// a bug in ActiveXObject prevents us from properly testing for it.
++CsrfMagic = function(real) {
++ // try to make it ourselves, if you didn't pass it
++ if (!real) try { real = new XMLHttpRequest; } catch (e) {;}
++ if (!real) try { real = new ActiveXObject('Msxml2.XMLHTTP'); } catch (e) {;}
++ if (!real) try { real = new ActiveXObject('Microsoft.XMLHTTP'); } catch (e) {;}
++ if (!real) try { real = new ActiveXObject('Msxml2.XMLHTTP.4.0'); } catch (e) {;}
++ this.csrf = real;
++ // properties
++ var csrfMagic = this;
++ real.onreadystatechange = function() {
++ csrfMagic._updateProps();
++ return csrfMagic.onreadystatechange ? csrfMagic.onreadystatechange() : null;
++ };
++ csrfMagic._updateProps();
++}
++
++CsrfMagic.prototype = {
++
++ open: function(method, url, async, username, password) {
++ if (method == 'POST') this.csrf_isPost = true;
++ // deal with Opera bug, thanks jQuery
++ if (username) return this.csrf_open(method, url, async, username, password);
++ else return this.csrf_open(method, url, async);
++ },
++ csrf_open: function(method, url, async, username, password) {
++ if (username) return this.csrf.open(method, url, async, username, password);
++ else return this.csrf.open(method, url, async);
++ },
++
++ send: function(data) {
++ if (!this.csrf_isPost) return this.csrf_send(data);
++ prepend = csrfMagicName + '=' + csrfMagicToken + '&';
++ if (this.csrf_purportedLength === undefined) {
++ this.csrf_setRequestHeader("Content-length", this.csrf_purportedLength + prepend.length);
++ delete this.csrf_purportedLength;
++ }
++ delete this.csrf_isPost;
++ return this.csrf_send(prepend + data);
++ },
++ csrf_send: function(data) {
++ return this.csrf.send(data);
++ },
++
++ setRequestHeader: function(header, value) {
++ // We have to auto-set this at the end, since we don't know how long the
++ // nonce is when added to the data.
++ if (this.csrf_isPost && header == "Content-length") {
++ this.csrf_purportedLength = value;
++ return;
++ }
++ return this.csrf_setRequestHeader(header, value);
++ },
++ csrf_setRequestHeader: function(header, value) {
++ return this.csrf.setRequestHeader(header, value);
++ },
++
++ abort: function() {
++ return this.csrf.abort();
++ },
++ getAllResponseHeaders: function() {
++ return this.csrf.getAllResponseHeaders();
++ },
++ getResponseHeader: function(header) {
++ return this.csrf.getResponseHeader(header);
++ } // ,
++}
++
++// proprietary
++CsrfMagic.prototype._updateProps = function() {
++ this.readyState = this.csrf.readyState;
++ if (this.readyState == 4) {
++ this.responseText = this.csrf.responseText;
++ this.responseXML = this.csrf.responseXML;
++ this.status = this.csrf.status;
++ this.statusText = this.csrf.statusText;
++ }
++}
++CsrfMagic.process = function(base) {
++ var prepend = csrfMagicName + '=' + csrfMagicToken;
++ if (base) return prepend + '&' + base;
++ return prepend;
++}
++// callback function for when everything on the page has loaded
++CsrfMagic.end = function() {
++ // This rewrites forms AGAIN, so in case buffering didn't work this
++ // certainly will.
++ forms = document.getElementsByTagName('form');
++ for (var i = 0; i < forms.length; i++) {
++ form = forms[i];
++ if (form.method.toUpperCase() !== 'POST') continue;
++ if (form.elements[csrfMagicName]) continue;
++ var input = document.createElement('input');
++ input.setAttribute('name', csrfMagicName);
++ input.setAttribute('value', csrfMagicToken);
++ input.setAttribute('type', 'hidden');
++ form.appendChild(input);
++ }
++}
++
++// Sets things up for Mozilla/Opera/nice browsers
++// We very specifically match against Internet Explorer, since they haven't
++// implemented prototypes correctly yet.
++if (window.XMLHttpRequest && window.XMLHttpRequest.prototype && '\v' != 'v') {
++ var x = XMLHttpRequest.prototype;
++ var c = CsrfMagic.prototype;
++
++ // Save the original functions
++ x.csrf_open = x.open;
++ x.csrf_send = x.send;
++ x.csrf_setRequestHeader = x.setRequestHeader;
++
++ // Notice that CsrfMagic is itself an instantiatable object, but only
++ // open, send and setRequestHeader are necessary as decorators.
++ x.open = c.open;
++ x.send = c.send;
++ x.setRequestHeader = c.setRequestHeader;
++} else {
++ // The only way we can do this is by modifying a library you have been
++ // using. We support YUI, script.aculo.us, prototype, MooTools,
++ // jQuery, Ext and Dojo.
++ if (window.jQuery) {
++ // jQuery didn't implement a new XMLHttpRequest function, so we have
++ // to do this the hard way.
++ jQuery.csrf_ajax = jQuery.ajax;
++ jQuery.ajax = function( s ) {
++ if (s.type && s.type.toUpperCase() == 'POST') {
++ s = jQuery.extend(true, s, jQuery.extend(true, {}, jQuery.ajaxSettings, s));
++ if ( s.data && s.processData && typeof s.data != "string" ) {
++ s.data = jQuery.param(s.data);
++ }
++ s.data = CsrfMagic.process(s.data);
++ }
++ return jQuery.csrf_ajax( s );
++ }
++ }
++ if (window.Prototype) {
++ // This works for script.aculo.us too
++ Ajax.csrf_getTransport = Ajax.getTransport;
++ Ajax.getTransport = function() {
++ return new CsrfMagic(Ajax.csrf_getTransport());
++ }
++ }
++ if (window.MooTools) {
++ Browser.csrf_Request = Browser.Request;
++ Browser.Request = function () {
++ return new CsrfMagic(Browser.csrf_Request());
++ }
++ }
++ if (window.YAHOO) {
++ // old YUI API
++ YAHOO.util.Connect.csrf_createXhrObject = YAHOO.util.Connect.createXhrObject;
++ YAHOO.util.Connect.createXhrObject = function (transaction) {
++ obj = YAHOO.util.Connect.csrf_createXhrObject(transaction);
++ obj.conn = new CsrfMagic(obj.conn);
++ return obj;
++ }
++ }
++ if (window.Ext) {
++ // Ext can use other js libraries as loaders, so it has to come last
++ // Ext's implementation is pretty identical to Yahoo's, but we duplicate
++ // it for comprehensiveness's sake.
++ Ext.lib.Ajax.csrf_createXhrObject = Ext.lib.Ajax.createXhrObject;
++ Ext.lib.Ajax.createXhrObject = function (transaction) {
++ obj = Ext.lib.Ajax.csrf_createXhrObject(transaction);
++ obj.conn = new CsrfMagic(obj.conn);
++ return obj;
++ }
++ }
++ if (window.dojo) {
++ // NOTE: this doesn't work with latest dojo
++ dojo.csrf__xhrObj = dojo._xhrObj;
++ dojo._xhrObj = function () {
++ return new CsrfMagic(dojo.csrf__xhrObj());
++ }
++ }
++}
+--- /dev/null
++++ b/include/csrf/csrf-magic.php
+@@ -0,0 +1,403 @@
++
++ */
++$GLOBALS['csrf']['input-name'] = '__csrf_magic';
++
++/**
++ * Set this to false if your site must work inside of frame/iframe elements,
++ * but do so at your own risk: this configuration protects you against CSS
++ * overlay attacks that defeat tokens.
++ */
++$GLOBALS['csrf']['frame-breaker'] = true;
++
++/**
++ * Whether or not CSRF Magic should be allowed to start a new session in order
++ * to determine the key.
++ */
++$GLOBALS['csrf']['auto-session'] = true;
++
++/**
++ * Whether or not csrf-magic should produce XHTML style tags.
++ */
++$GLOBALS['csrf']['xhtml'] = true;
++
++// FUNCTIONS:
++
++// Don't edit this!
++$GLOBALS['csrf']['version'] = '1.0.4';
++
++/**
++ * Rewrites
++
CSRF check failed. Your form session may have expired, or you may not have
++ cookies enabled.
++
++
Debug: $tokens
', $script . '', $buffer, $count);
++ if (!$count) {
++ $buffer .= $script;
++ }
++ }
++ return $buffer;
++}
++
++/**
++ * Checks if this is a post request, and if it is, checks if the nonce is valid.
++ * @param bool $fatal Whether or not to fatally error out if there is a problem.
++ * @return True if check passes or is not necessary, false if failure.
++ */
++function csrf_check($fatal = true) {
++ if (!isset($_SERVER['REQUEST_METHOD']) || ($_SERVER['REQUEST_METHOD'] !== 'POST')) return true;
++ csrf_start();
++ $name = $GLOBALS['csrf']['input-name'];
++ $ok = false;
++ $tokens = '';
++ do {
++ if (!isset($_POST[$name])) break;
++ // we don't regenerate a token and check it because some token creation
++ // schemes are volatile.
++ $tokens = $_POST[$name];
++ if (!csrf_check_tokens($tokens)) break;
++ $ok = true;
++ } while (false);
++ if ($fatal && !$ok) {
++ $callback = $GLOBALS['csrf']['callback'];
++ if (trim($tokens, 'A..Za..z0..9:;,') !== '') $tokens = 'hidden';
++ $callback($tokens);
++ exit;
++ }
++ return $ok;
++}
++
++/**
++ * Retrieves a valid token(s) for a particular context. Tokens are separated
++ * by semicolons.
++ */
++function csrf_get_tokens() {
++ $has_cookies = !empty($_COOKIE);
++
++ // $ip implements a composite key, which is sent if the user hasn't sent
++ // any cookies. It may or may not be used, depending on whether or not
++ // the cookies "stick"
++ $secret = csrf_get_secret();
++ if (!$has_cookies && $secret) {
++ // :TODO: Harden this against proxy-spoofing attacks
++ $ip = ';ip:' . csrf_hash($_SERVER['IP_ADDRESS']);
++ } else {
++ $ip = '';
++ }
++ csrf_start();
++
++ // These are "strong" algorithms that don't require per se a secret
++ if (session_id()) return 'sid:' . csrf_hash(session_id()) . $ip;
++ if ($GLOBALS['csrf']['cookie']) {
++ $val = csrf_generate_secret();
++ setcookie($GLOBALS['csrf']['cookie'], $val);
++ return 'cookie:' . csrf_hash($val) . $ip;
++ }
++ if ($GLOBALS['csrf']['key']) return 'key:' . csrf_hash($GLOBALS['csrf']['key']) . $ip;
++ // These further algorithms require a server-side secret
++ if (!$secret) return 'invalid';
++ if ($GLOBALS['csrf']['user'] !== false) {
++ return 'user:' . csrf_hash($GLOBALS['csrf']['user']);
++ }
++ if ($GLOBALS['csrf']['allow-ip']) {
++ return ltrim($ip, ';');
++ }
++ return 'invalid';
++}
++
++function csrf_flattenpost($data) {
++ $ret = array();
++ foreach($data as $n => $v) {
++ $ret = array_merge($ret, csrf_flattenpost2(1, $n, $v));
++ }
++ return $ret;
++}
++function csrf_flattenpost2($level, $key, $data) {
++ if(!is_array($data)) return array($key => $data);
++ $ret = array();
++ foreach($data as $n => $v) {
++ $nk = $level >= 1 ? $key."[$n]" : "[$n]";
++ $ret = array_merge($ret, csrf_flattenpost2($level+1, $nk, $v));
++ }
++ return $ret;
++}
++
++/**
++ * @param $tokens is safe for HTML consumption
++ */
++function csrf_callback($tokens) {
++ // (yes, $tokens is safe to echo without escaping)
++ header($_SERVER['SERVER_PROTOCOL'] . ' 403 Forbidden');
++ $data = '';
++ foreach (csrf_flattenpost($_POST) as $key => $value) {
++ if ($key == $GLOBALS['csrf']['input-name']) continue;
++ $data .= '';
++ }
++ echo "