Brian May <b...@debian.org> writes: > I have patched a number of vulnerabilities in phpmyadmin in wheezy; > there is a version available for testing at > https://people.debian.org/~bam/debian/pool/main/p/phpmyadmin/
> The included isAllowedDomain does not include some checks that are in > later versions: I have now added these checks, and updated the package available at the above URL. The updated debdiff is below. diff -Nru phpmyadmin-3.4.11.1/debian/changelog phpmyadmin-3.4.11.1/debian/changelog --- phpmyadmin-3.4.11.1/debian/changelog 2016-09-15 07:17:16.000000000 +1000 +++ phpmyadmin-3.4.11.1/debian/changelog 2016-12-06 08:18:14.000000000 +1100 @@ -1,3 +1,25 @@ +phpmyadmin (4:3.4.11.1-2+deb7u7) wheezy-security; urgency=high + + * Non-maintainer upload by the LTS Team. + * CVE-2016-4412 / PMASA-2016-57: A user can be tricked in to following a + link leading to phpMyAdmin, which after authentication redirects to + another malicious site. + * CVE-2016-6626 / PMASA-2016-49: In the fix for PMASA-2016-57, we didn't + have sufficient checking and was possible to bypass whitelist. + * CVE-2016-9849 / PMASA-2016-60: Username deny rules bypass (AllowRoot & + Others) by using Null Byte. + * CVE-2016-9850 / PMASA-2016-61: Username matching for the allow/deny rules + may result in wrong matches and detection of the username in the rule due + to non-constant execution time. + * CVE-2016-9861 / PMASA-2016-66: In the fix for PMASA-2016-49, we has buggy + checks and was possible to bypass whitelist. + * CVE-2016-9864 / PMASA-2016-69: Multiple SQL injection vulnerabilities. + * CVE-2016-9865 / PMASA-2016-70: Due to a bug in serialized string parsing, + it was possible to bypass the protection offered by PMA_safeUnserialize() + function. + + -- Brian May <b...@debian.org> Tue, 06 Dec 2016 08:18:14 +1100 + phpmyadmin (4:3.4.11.1-2+deb7u6) wheezy-security; urgency=high * Non-maintainer upload by the Long Term Security Team. diff -Nru phpmyadmin-3.4.11.1/debian/patches/pmasa-2016-49.patch phpmyadmin-3.4.11.1/debian/patches/pmasa-2016-49.patch --- phpmyadmin-3.4.11.1/debian/patches/pmasa-2016-49.patch 1970-01-01 10:00:00.000000000 +1000 +++ phpmyadmin-3.4.11.1/debian/patches/pmasa-2016-49.patch 2016-12-06 08:18:14.000000000 +1100 @@ -0,0 +1,13 @@ +--- a/libraries/core.lib.php ++++ b/libraries/core.lib.php +@@ -864,6 +864,10 @@ + function PMA_isAllowedDomain($url) + { + $arr = parse_url($url); ++ // Avoid URLs without hostname or with credentials ++ if (empty($arr['host']) || ! empty($arr['user']) || ! empty($arr['pass'])) { ++ return false; ++ } + $domain = $arr["host"]; + $domainWhiteList = array( + /* Include current domain */ diff -Nru phpmyadmin-3.4.11.1/debian/patches/pmasa-2016-57.patch phpmyadmin-3.4.11.1/debian/patches/pmasa-2016-57.patch --- phpmyadmin-3.4.11.1/debian/patches/pmasa-2016-57.patch 1970-01-01 10:00:00.000000000 +1000 +++ phpmyadmin-3.4.11.1/debian/patches/pmasa-2016-57.patch 2016-12-06 08:18:14.000000000 +1100 @@ -0,0 +1,68 @@ +--- a/libraries/core.lib.php ++++ b/libraries/core.lib.php +@@ -852,4 +852,38 @@ + + return unserialize($data); + } ++ ++/** ++ * Checks whether domain of URL is whitelisted domain or not. ++ * Use only for URLs of external sites. ++ * ++ * @param string $url URL of external site. ++ * ++ * @return boolean.True:if domain of $url is allowed domain, False:otherwise. ++ */ ++function PMA_isAllowedDomain($url) ++{ ++ $arr = parse_url($url); ++ $domain = $arr["host"]; ++ $domainWhiteList = array( ++ /* Include current domain */ ++ $_SERVER['SERVER_NAME'], ++ /* phpMyAdmin domains */ ++ 'wiki.phpmyadmin.net', 'www.phpmyadmin.net', 'phpmyadmin.net', ++ 'docs.phpmyadmin.net', ++ /* mysql.com domains */ ++ 'dev.mysql.com','bugs.mysql.com', ++ /* php.net domains */ ++ 'php.net', ++ /* Github domains*/ ++ 'github.com','www.github.com', ++ /* Following are doubtful ones. */ ++ 'www.primebase.com','pbxt.blogspot.com' ++ ); ++ if (in_array(strtolower($domain), $domainWhiteList)) { ++ return true; ++ } ++ ++ return false; ++} + ?> +--- a/url.php ++++ b/url.php +@@ -8,9 +8,22 @@ + */ + require_once './libraries/common.inc.php'; + +-if (! PMA_isValid($_GET['url']) || ! preg_match('/^https?:\/\/[^\n\r]*$/', $_GET['url'])) { ++if (! PMA_isValid($_GET['url']) ++ || ! preg_match('/^https?:\/\/[^\n\r]*$/', $_GET['url']) ++ || ! PMA_isAllowedDomain($_GET['url']) ++) { + header('Location: ' . $cfg['PmaAbsoluteUri']); + } else { +- header('Location: ' . $_GET['url']); ++ // JavaScript redirection is necessary. Because if header() is used ++ // then web browser sometimes does not change the HTTP_REFERER ++ // field and so with old URL as Referer, token also goes to ++ // external site. ++ echo "<script type='text/javascript'> ++ window.onload=function(){ ++ window.location='" . PMA_escapeJsString($_GET['url']) . "'; ++ } ++ </script>"; ++ // Display redirecting msg on screen. ++ printf(__('Taking you to %s.'), htmlspecialchars($_GET['url'])); + } + ?> diff -Nru phpmyadmin-3.4.11.1/debian/patches/pmasa-2016-60.patch phpmyadmin-3.4.11.1/debian/patches/pmasa-2016-60.patch --- phpmyadmin-3.4.11.1/debian/patches/pmasa-2016-60.patch 1970-01-01 10:00:00.000000000 +1000 +++ phpmyadmin-3.4.11.1/debian/patches/pmasa-2016-60.patch 2016-12-06 08:18:14.000000000 +1100 @@ -0,0 +1,50 @@ +--- a/libraries/auth/cookie.auth.lib.php ++++ b/libraries/auth/cookie.auth.lib.php +@@ -432,7 +432,7 @@ + + if (! empty($_REQUEST['pma_username'])) { + // The user just logged in +- $GLOBALS['PHP_AUTH_USER'] = $_REQUEST['pma_username']; ++ $GLOBALS['PHP_AUTH_USER'] = PMA_sanitizeMySQLUser($_REQUEST['pma_username']); + $GLOBALS['PHP_AUTH_PW'] = empty($_REQUEST['pma_password']) ? '' : $_REQUEST['pma_password']; + if ($GLOBALS['cfg']['AllowArbitraryServer'] && isset($_REQUEST['pma_servername'])) { + $GLOBALS['pma_auth_server'] = PMA_sanitizeMySQLHost($_REQUEST['pma_servername']); +--- a/libraries/core.lib.php ++++ b/libraries/core.lib.php +@@ -766,6 +766,24 @@ + } + + /** ++ * Sanitizes MySQL username ++ * ++ * * strips part behind null byte ++ * ++ * @param string $name User given username ++ * ++ * @return string ++ */ ++function PMA_sanitizeMySQLUser($name) ++{ ++ $position = strpos($name, chr(0)); ++ if ($position !== false) { ++ return substr($name, 0, $position); ++ } ++ return $name; ++} ++ ++/** + * Safe unserializer wrapper + * + * It does not unserialize data containing objects +--- a/libraries/auth/http.auth.lib.php ++++ b/libraries/auth/http.auth.lib.php +@@ -155,6 +155,9 @@ + unset($usr_pass); + } + ++ // sanitize username ++ $PHP_AUTH_USER = PMA_sanitizeMySQLUser($PHP_AUTH_USER); ++ + // User logged out -> ensure the new username is not the same + if (!empty($old_usr) + && (isset($PHP_AUTH_USER) && $old_usr == $PHP_AUTH_USER)) { diff -Nru phpmyadmin-3.4.11.1/debian/patches/pmasa-2016-61-1.patch phpmyadmin-3.4.11.1/debian/patches/pmasa-2016-61-1.patch --- phpmyadmin-3.4.11.1/debian/patches/pmasa-2016-61-1.patch 1970-01-01 10:00:00.000000000 +1000 +++ phpmyadmin-3.4.11.1/debian/patches/pmasa-2016-61-1.patch 2016-12-06 08:18:14.000000000 +1100 @@ -0,0 +1,11 @@ +--- a/libraries/ip_allow_deny.lib.php ++++ b/libraries/ip_allow_deny.lib.php +@@ -169,7 +169,7 @@ + + // check for username + if (($rule_data[1] != '%') //wildcarded first +- && ($rule_data[1] != $username)) { ++ && (! hash_equals($rule_data[1], $username))) { + continue; + } + diff -Nru phpmyadmin-3.4.11.1/debian/patches/pmasa-2016-61-2.patch phpmyadmin-3.4.11.1/debian/patches/pmasa-2016-61-2.patch --- phpmyadmin-3.4.11.1/debian/patches/pmasa-2016-61-2.patch 1970-01-01 10:00:00.000000000 +1000 +++ phpmyadmin-3.4.11.1/debian/patches/pmasa-2016-61-2.patch 2016-12-06 08:18:14.000000000 +1100 @@ -0,0 +1,45 @@ +--- a/libraries/auth/cookie.auth.lib.php ++++ b/libraries/auth/cookie.auth.lib.php +@@ -524,14 +524,14 @@ + + // Ensures valid authentication mode, 'only_db', bookmark database and + // table names and relation table name are used +- if ($cfg['Server']['user'] != $GLOBALS['PHP_AUTH_USER']) { ++ if (! hash_equals($cfg['Server']['user'], $GLOBALS['PHP_AUTH_USER'])) { + foreach ($cfg['Servers'] as $idx => $current) { + if ($current['host'] == $cfg['Server']['host'] + && $current['port'] == $cfg['Server']['port'] + && $current['socket'] == $cfg['Server']['socket'] + && $current['ssl'] == $cfg['Server']['ssl'] + && $current['connect_type'] == $cfg['Server']['connect_type'] +- && $current['user'] == $GLOBALS['PHP_AUTH_USER']) { ++ && hash_equals($current['user'], $GLOBALS['PHP_AUTH_USER'])) { + $GLOBALS['server'] = $idx; + $cfg['Server'] = $current; + break; +--- a/libraries/auth/http.auth.lib.php ++++ b/libraries/auth/http.auth.lib.php +@@ -160,7 +160,7 @@ + + // User logged out -> ensure the new username is not the same + if (!empty($old_usr) +- && (isset($PHP_AUTH_USER) && $old_usr == $PHP_AUTH_USER)) { ++ && (isset($PHP_AUTH_USER) && hash_equals($old_usr, $PHP_AUTH_USER))) { + $PHP_AUTH_USER = ''; + // -> delete user's choices that were stored in session + session_destroy(); +@@ -195,11 +195,12 @@ + + // Ensures valid authentication mode, 'only_db', bookmark database and + // table names and relation table name are used +- if ($cfg['Server']['user'] != $PHP_AUTH_USER) { ++ if (! hash_equals($cfg['Server']['user'], $PHP_AUTH_USER)) { + $servers_cnt = count($cfg['Servers']); + for ($i = 1; $i <= $servers_cnt; $i++) { + if (isset($cfg['Servers'][$i]) +- && ($cfg['Servers'][$i]['host'] == $cfg['Server']['host'] && $cfg['Servers'][$i]['user'] == $PHP_AUTH_USER)) { ++ && $cfg['Servers'][$i]['host'] == $cfg['Server']['host'] ++ && hash_equals($cfg['Servers'][$i]['user'], $PHP_AUTH_USER)) { + $server = $i; + $cfg['Server'] = $cfg['Servers'][$i]; + break; diff -Nru phpmyadmin-3.4.11.1/debian/patches/pmasa-2016-66.patch phpmyadmin-3.4.11.1/debian/patches/pmasa-2016-66.patch --- phpmyadmin-3.4.11.1/debian/patches/pmasa-2016-66.patch 1970-01-01 10:00:00.000000000 +1000 +++ phpmyadmin-3.4.11.1/debian/patches/pmasa-2016-66.patch 2016-12-06 08:18:14.000000000 +1100 @@ -0,0 +1,31 @@ +--- a/libraries/core.lib.php ++++ b/libraries/core.lib.php +@@ -882,10 +882,17 @@ + function PMA_isAllowedDomain($url) + { + $arr = parse_url($url); +- // Avoid URLs without hostname or with credentials +- if (empty($arr['host']) || ! empty($arr['user']) || ! empty($arr['pass'])) { ++ // We need host to be set ++ if (! isset($arr['host']) || strlen($arr['host']) == 0) { + return false; + } ++ // We do not want these to be present ++ $blocked = array('user', 'pass', 'port'); ++ foreach ($blocked as $part) { ++ if (isset($arr[$part]) && strlen($arr[$part]) != 0) { ++ return false; ++ } ++ } + $domain = $arr["host"]; + $domainWhiteList = array( + /* Include current domain */ +@@ -902,7 +909,7 @@ + /* Following are doubtful ones. */ + 'www.primebase.com','pbxt.blogspot.com' + ); +- if (in_array(strtolower($domain), $domainWhiteList)) { ++ if (in_array($domain, $domainWhiteList)) { + return true; + } + diff -Nru phpmyadmin-3.4.11.1/debian/patches/pmasa-2016-69-1.patch phpmyadmin-3.4.11.1/debian/patches/pmasa-2016-69-1.patch --- phpmyadmin-3.4.11.1/debian/patches/pmasa-2016-69-1.patch 1970-01-01 10:00:00.000000000 +1000 +++ phpmyadmin-3.4.11.1/debian/patches/pmasa-2016-69-1.patch 2016-12-06 08:18:14.000000000 +1100 @@ -0,0 +1,13 @@ +--- a/libraries/Tracker.class.php ++++ b/libraries/Tracker.class.php +@@ -240,8 +240,9 @@ + static public function getLogComment() + { + $date = date('Y-m-d H:i:s'); ++ $user = preg_replace('/\s+/', ' ', $GLOBALS['cfg']['Server']['user']); + +- return "# log " . $date . " " . $GLOBALS['cfg']['Server']['user'] . "\n"; ++ return "# log " . $date . " " . $user . "\n"; + } + + /** diff -Nru phpmyadmin-3.4.11.1/debian/patches/pmasa-2016-69-2.patch phpmyadmin-3.4.11.1/debian/patches/pmasa-2016-69-2.patch --- phpmyadmin-3.4.11.1/debian/patches/pmasa-2016-69-2.patch 1970-01-01 10:00:00.000000000 +1000 +++ phpmyadmin-3.4.11.1/debian/patches/pmasa-2016-69-2.patch 2016-12-06 08:18:14.000000000 +1100 @@ -0,0 +1,20 @@ +--- a/tbl_tracking.php ++++ b/tbl_tracking.php +@@ -106,13 +106,15 @@ + if (isset($_REQUEST['report_export']) && $_REQUEST['export_type'] == 'sqldumpfile') { + @ini_set('url_rewriter.tags',''); + +- $dump = "# " . sprintf(__('Tracking report for table `%s`'), htmlspecialchars($_REQUEST['table'])) . "\n" . ++ // Replace all multiple whitespaces by a single space ++ $table = htmlspecialchars(preg_replace('/\s+/', ' ', $_REQUEST['table'])); ++ $dump = "# " . sprintf(__('Tracking report for table `%s`'), $table) . "\n" . + "# " . date('Y-m-d H:i:s') . "\n"; + foreach($entries as $entry) { + $dump .= $entry['statement']; + } + //$filename = 'log_' . str_replace(';', '', htmlspecialchars($_REQUEST['table'])) . '.sql'; +- $filename = PMA_sanitize_filename('log_' . $_REQUEST['table'] . '.sql'); ++ $filename = PMA_sanitize_filename('log_' . $table . '.sql'); + header('Content-Type: text/x-sql'); + header('Expires: ' . gmdate('D, d M Y H:i:s') . ' GMT'); + header('Content-Disposition: attachment; filename="' . $filename . '"'); diff -Nru phpmyadmin-3.4.11.1/debian/patches/pmasa-2016-70.patch phpmyadmin-3.4.11.1/debian/patches/pmasa-2016-70.patch --- phpmyadmin-3.4.11.1/debian/patches/pmasa-2016-70.patch 1970-01-01 10:00:00.000000000 +1000 +++ phpmyadmin-3.4.11.1/debian/patches/pmasa-2016-70.patch 2016-12-06 08:18:14.000000000 +1100 @@ -0,0 +1,25 @@ +From 5e108a340f3eac6b6c488439343b6c1a7454787c Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Michal=20=C4=8Ciha=C5=99?= <mic...@cihar.com> +Date: Tue, 4 Oct 2016 13:17:07 +0200 +Subject: [PATCH] Correctly parse string length when checking serialized data +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Signed-off-by: Michal Čihař <mic...@cihar.com> +--- + libraries/core.lib.php | 2 +- + test/libraries/core/PMA_safeUnserialize_test.php | 1 + + 2 files changed, 2 insertions(+), 1 deletion(-) + +--- a/libraries/core.lib.php ++++ b/libraries/core.lib.php +@@ -816,7 +816,7 @@ + case 's': + /* string */ + // parse sting length +- $strlen = intval($data[$i + 2]); ++ $strlen = intval(substr($data, $i + 2)); + // string start + $i = strpos($data, ':', $i + 2); + if ($i === false) { diff -Nru phpmyadmin-3.4.11.1/debian/patches/series phpmyadmin-3.4.11.1/debian/patches/series --- phpmyadmin-3.4.11.1/debian/patches/series 2016-09-15 07:03:37.000000000 +1000 +++ phpmyadmin-3.4.11.1/debian/patches/series 2016-12-06 08:18:14.000000000 +1100 @@ -32,3 +32,12 @@ CVE-2016-6623.patch CVE-2016-6624.patch CVE-2016-6622.patch +pmasa-2016-57.patch +pmasa-2016-49.patch +pmasa-2016-60.patch +pmasa-2016-61-1.patch +pmasa-2016-61-2.patch +pmasa-2016-66.patch +pmasa-2016-69-1.patch +pmasa-2016-69-2.patch +pmasa-2016-70.patch -- Brian May <b...@debian.org>