diff --git a/ChangeLog b/ChangeLog index f53c063a0..81670e91e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -19,6 +19,9 @@ $HeadURL: https://phpmyadmin.svn.sourceforge.net/svnroot/phpmyadmin/trunk/phpMyA - bug #3044189 [doc] Cleared documentation for hide_db. - bug #3042495 [core] Move PMA_sendHeaderLocation to core.lib.php. +3.3.5.1 (2010-10-20) +- [core] Fixed various XSS issues, see PMASA-2010-5 for more details. + 3.3.5.0 (2010-07-26) - patch #2932113 [information_schema] Slow export when having lots of databases, thanks to Stéphane Pontier - shadow_walker diff --git a/db_search.php b/db_search.php index 751675db5..455aa61a1 100644 --- a/db_search.php +++ b/db_search.php @@ -355,7 +355,7 @@ $alter_select = + value="" /> diff --git a/db_sql.php b/db_sql.php index 2ac198bda..420561e81 100644 --- a/db_sql.php +++ b/db_sql.php @@ -37,7 +37,7 @@ if ($num_tables == 0 && empty($db_query_force)) { /** * Query box, bookmark, insert data from textfile */ -PMA_sqlQueryForm(true, false, isset($_REQUEST['delimiter']) ? $_REQUEST['delimiter'] : ';'); +PMA_sqlQueryForm(true, false, isset($_REQUEST['delimiter']) ? htmlspecialchars($_REQUEST['delimiter']) : ';'); /** * Displays the footer diff --git a/error.php b/error.php index 674d08e0f..7e86ffb95 100644 --- a/error.php +++ b/error.php @@ -76,10 +76,14 @@ header('Content-Type: text/html; charset=' . $charset);

phpMyAdmin -

diff --git a/libraries/common.lib.php b/libraries/common.lib.php index 1a62769f4..d5b38cc58 100644 --- a/libraries/common.lib.php +++ b/libraries/common.lib.php @@ -575,7 +575,7 @@ function PMA_mysqlDie($error_message = '', $the_query = '', $formatted_sql = ''; } else { if (strlen($the_query) > $GLOBALS['cfg']['MaxCharactersInDisplayedSQL']) { - $formatted_sql = substr($the_query, 0, $GLOBALS['cfg']['MaxCharactersInDisplayedSQL']) . '[...]'; + $formatted_sql = htmlspecialchars(substr($the_query, 0, $GLOBALS['cfg']['MaxCharactersInDisplayedSQL'])) . '[...]'; } else { $formatted_sql = PMA_formatSql(PMA_SQP_parse($the_query), $the_query); } diff --git a/libraries/core.lib.php b/libraries/core.lib.php index 3e6cc00ca..f7f9da4d7 100644 --- a/libraries/core.lib.php +++ b/libraries/core.lib.php @@ -614,22 +614,23 @@ function PMA_setCookie($cookie, $value, $default = null, $validity = null, $http function PMA_sendHeaderLocation($uri) { if (PMA_IS_IIS && strlen($uri) > 600) { + require_once './libraries/js_escape.lib.php'; echo '- - -' . "\n"; echo '' . "\n"; echo '' . "\n"; echo '' . "\n"; - echo '' . "\n"; + echo '' . "\n"; echo '' . "\n"; echo '' . "\n"; echo '' . "\n"; echo '' . "\n"; diff --git a/libraries/database_interface.lib.php b/libraries/database_interface.lib.php index 501c34d0c..300a92554 100644 --- a/libraries/database_interface.lib.php +++ b/libraries/database_interface.lib.php @@ -205,6 +205,10 @@ function PMA_usort_comparison_callback($a, $b) } else { $sorter = 'strcasecmp'; } + /* No sorting when key is not present */ + if (!isset($a[$GLOBALS['callback_sort_by']]) || ! isset($b[$GLOBALS['callback_sort_by']])) { + return 0; + } // produces f.e.: // return -1 * strnatcasecmp($a["SCHEMA_TABLES"], $b["SCHEMA_TABLES"]) return ($GLOBALS['callback_sort_order'] == 'ASC' ? 1 : -1) * $sorter($a[$GLOBALS['callback_sort_by']], $b[$GLOBALS['callback_sort_by']]); diff --git a/libraries/db_info.inc.php b/libraries/db_info.inc.php index 4f59baa47..1e5b401ad 100644 --- a/libraries/db_info.inc.php +++ b/libraries/db_info.inc.php @@ -213,7 +213,8 @@ if (! isset($sot_ready)) { ); // Make sure the sort type is implemented - if ($sort = $sortable_name_mappings[$_REQUEST['sort']]) { + if (isset($sortable_name_mappings[$_REQUEST['sort']])) { + $sort = $sortable_name_mappings[$_REQUEST['sort']]; if ($_REQUEST['sort_order'] == 'DESC') { $sort_order = 'DESC'; } diff --git a/libraries/dbi/mysql.dbi.lib.php b/libraries/dbi/mysql.dbi.lib.php index 275458832..4750ee225 100644 --- a/libraries/dbi/mysql.dbi.lib.php +++ b/libraries/dbi/mysql.dbi.lib.php @@ -348,6 +348,8 @@ function PMA_DBI_getError($link = null) $error_message = PMA_DBI_convert_message($error_message); } + $error_message = htmlspecialchars($error_message); + // Some errors messages cannot be obtained by mysql_error() if ($error_number == 2002) { $error = '#' . ((string) $error_number) . ' - ' . $GLOBALS['strServerNotResponding'] . ' ' . $GLOBALS['strSocketProblem']; diff --git a/libraries/dbi/mysqli.dbi.lib.php b/libraries/dbi/mysqli.dbi.lib.php index f3bcf268c..9672385df 100644 --- a/libraries/dbi/mysqli.dbi.lib.php +++ b/libraries/dbi/mysqli.dbi.lib.php @@ -405,6 +405,8 @@ function PMA_DBI_getError($link = null) $error_message = PMA_DBI_convert_message($error_message); } + $error_message = htmlspecialchars($error_message); + if ($error_number == 2002) { $error = '#' . ((string) $error_number) . ' - ' . $GLOBALS['strServerNotResponding'] . ' ' . $GLOBALS['strSocketProblem']; } else { diff --git a/libraries/sanitizing.lib.php b/libraries/sanitizing.lib.php index 2b54bf197..d17fc50dd 100644 --- a/libraries/sanitizing.lib.php +++ b/libraries/sanitizing.lib.php @@ -9,17 +9,26 @@ /** * Sanitizes $message, taking into account our special codes - * for formatting + * for formatting. + * + * If you want to include result in element attribute, you should escape it. + * + * Examples: + * + *

+ * + * bar * * @uses preg_replace() * @uses strtr() * @param string the message + * @param boolean whether to escape html in result * * @return string the sanitized message * * @access public */ -function PMA_sanitize($message) +function PMA_sanitize($message, $escape = false) { $replace_pairs = array( '<' => '<', @@ -67,6 +76,10 @@ function PMA_sanitize($message) $message = preg_replace($pattern, '', $message); } + if ($escape) { + $message = htmlspecialchars($message); + } + return $message; } ?> diff --git a/libraries/sqlparser.lib.php b/libraries/sqlparser.lib.php index 53f239a97..f844e2301 100644 --- a/libraries/sqlparser.lib.php +++ b/libraries/sqlparser.lib.php @@ -2456,7 +2456,7 @@ if (! defined('PMA_MINIMUM_COMMON')) { } $after .= "\n"; */ - $str .= $before . ($mode=='color' ? PMA_SQP_formatHTML_colorize($arr[$i]) : $arr[$i]['data']). $after; + $str .= $before . ($mode=='color' ? PMA_SQP_formatHTML_colorize($arr[$i]) : htmlspecialchars($arr[$i]['data'])). $after; } // end for if ($mode=='color') { $str .= ''; diff --git a/server_databases.php b/server_databases.php index 47037cc66..5e6d0ecc4 100644 --- a/server_databases.php +++ b/server_databases.php @@ -22,7 +22,21 @@ require './libraries/replication.inc.php'; if (empty($_REQUEST['sort_by'])) { $sort_by = 'SCHEMA_NAME'; } else { - $sort_by = PMA_sanitize($_REQUEST['sort_by']); + $sort_by_whitelist = array( + 'SCHEMA_NAME', + 'DEFAULT_COLLATION_NAME', + 'SCHEMA_TABLES', + 'SCHEMA_TABLE_ROWS', + 'SCHEMA_DATA_LENGTH', + 'SCHEMA_INDEX_LENGTH', + 'SCHEMA_LENGTH', + 'SCHEMA_DATA_FREE' + ); + if (in_array($_REQUEST['sort_by'], $sort_by_whitelist)) { + $sort_by = $_REQUEST['sort_by']; + } else { + $sort_by = 'SCHEMA_NAME'; + } } if (isset($_REQUEST['sort_order']) @@ -342,11 +356,11 @@ if ($databases_count > 0) { unset($column_order, $stat_name, $stat, $databases, $table_columns); if ($is_superuser || $cfg['AllowUserDropDatabase']) { - $common_url_query = PMA_generate_common_url() . '&sort_by=' . $sort_by . '&sort_order=' . $sort_order . '&dbstats=' . $dbstats; + $common_url_query = PMA_generate_common_url(array('sort_by' => $sort_by, 'sort_order' => $sort_order, 'dbstats' => $dbstats)); echo '' . $strWithChecked . '' . "\n" - . '' . "\n" + . '' . "\n" . ' ' . $strCheckAll . ' / ' . "\n" - . '' . "\n" + . '' . "\n" . ' ' . $strUncheckAll . '' . "\n" . '' . $strWithChecked . '' . "\n"; PMA_buttonOrImage('drop_selected_dbs', 'mult_submit', 'drop_selected_dbs', $strDrop, 'b_deltbl.png'); diff --git a/server_privileges.php b/server_privileges.php index 3f14c3f93..44e9be74d 100644 --- a/server_privileges.php +++ b/server_privileges.php @@ -1153,7 +1153,7 @@ if (!empty($update_privs)) { } $sql_query = $sql_query0 . ' ' . $sql_query1 . ' ' . $sql_query2; $message = PMA_Message::success('strUpdatePrivMessage'); - $message->addParam('\'' . $username . '\'@\'' . $hostname . '\''); + $message->addParam('\'' . htmlspecialchars($username) . '\'@\'' . htmlspecialchars($hostname) . '\''); } @@ -1177,7 +1177,7 @@ if (isset($_REQUEST['revokeall'])) { } $sql_query = $sql_query0 . ' ' . $sql_query1; $message = PMA_Message::success('strRevokeMessage'); - $message->addParam('\'' . $username . '\'@\'' . $hostname . '\''); + $message->addParam('\'' . htmlspecialchars($username) . '\'@\'' . htmlspecialchars($hostname) . '\''); if (! isset($tablename)) { unset($dbname); } else { @@ -1213,7 +1213,7 @@ if (isset($_REQUEST['change_pw'])) { PMA_DBI_try_query($local_query) or PMA_mysqlDie(PMA_DBI_getError(), $sql_query, FALSE, $err_url); $message = PMA_Message::success('strPasswordChanged'); - $message->addParam('\'' . $username . '\'@\'' . $hostname . '\''); + $message->addParam('\'' . htmlspecialchars($username) . '\'@\'' . htmlspecialchars($hostname) . '\''); } } @@ -1595,8 +1595,8 @@ if (empty($_REQUEST['adduser']) && (! isset($checkprivs) || ! strlen($checkprivs if (isset($dbname)) { echo ' \'' + . $GLOBALS['url_query'] . '&username=' . htmlspecialchars(urlencode($username)) + . '&hostname=' . htmlspecialchars(urlencode($hostname)) . '&dbname=&tablename=">\'' . htmlspecialchars($username) . '\'@\'' . htmlspecialchars($hostname) . '\'' . "\n"; $url_dbname = urlencode(str_replace(array('\_', '\%'), array('_', '%'), $dbname)); @@ -1604,8 +1604,8 @@ if (empty($_REQUEST['adduser']) && (! isset($checkprivs) || ! strlen($checkprivs echo ' - ' . ($dbname_is_wildcard ? $GLOBALS['strDatabases'] : $GLOBALS['strDatabase'] ); if (isset($tablename)) { echo ' ' . htmlspecialchars($dbname) . ''; + . '&username=' . htmlspecialchars(urlencode($username)) . '&hostname=' . htmlspecialchars(urlencode($hostname)) + . '&dbname=' . htmlspecialchars($url_dbname) . '&tablename=">' . htmlspecialchars($dbname) . ''; echo ' - ' . $GLOBALS['strTable'] . ' ' . htmlspecialchars($tablename) . ''; } else { echo ' ' . htmlspecialchars($dbname) . ''; @@ -1839,16 +1839,16 @@ if (empty($_REQUEST['adduser']) && (! isset($checkprivs) || ! strlen($checkprivs } echo '' . "\n" . ' '; - printf($link_edit, urlencode($username), - urlencode($hostname), - urlencode((! isset($dbname)) ? $row['Db'] : $dbname), + printf($link_edit, htmlspecialchars(urlencode($username)), + urlencode(htmlspecialchars($hostname)), + urlencode((! isset($dbname)) ? $row['Db'] : htmlspecialchars($dbname)), urlencode((! isset($dbname)) ? '' : $row['Table_name'])); echo '' . "\n" . ' '; if (! empty($row['can_delete']) || isset($row['Table_name']) && strlen($row['Table_name'])) { - printf($link_revoke, urlencode($username), - urlencode($hostname), - urlencode((! isset($dbname)) ? $row['Db'] : $dbname), + printf($link_revoke, htmlspecialchars(urlencode($username)), + urlencode(htmlspecialchars($hostname)), + urlencode((! isset($dbname)) ? $row['Db'] : htmlspecialchars($dbname)), urlencode((! isset($dbname)) ? '' : $row['Table_name'])); } echo '' . "\n" @@ -1928,7 +1928,7 @@ if (empty($_REQUEST['adduser']) && (! isset($checkprivs) || ! strlen($checkprivs if (isset($tablename)) { echo ' [ ' . $GLOBALS['strTable'] . ' ' . htmlspecialchars($tablename) . ': ' . PMA_getTitleForTarget($GLOBALS['cfg']['DefaultTabTable']) . " ]\n"; @@ -2155,7 +2155,7 @@ if (empty($_REQUEST['adduser']) && (! isset($checkprivs) || ! strlen($checkprivs // Offer to create a new user for the current database echo '
' . "\n" - . ' ' . "\n" + . ' ' . "\n" . PMA_getIcon('b_usradd.png') . ' ' . $GLOBALS['strAddUser'] . '' . "\n" . '
' . "\n"; diff --git a/sql.php b/sql.php index 4dbfee246..b7281842d 100644 --- a/sql.php +++ b/sql.php @@ -175,14 +175,14 @@ if ($do_confirm) { .PMA_generate_common_hidden_inputs($db, $table); ?> - + - - - - - - + + + + + + ' . "\n" .' ' . $strDoYouReally . '' diff --git a/tbl_sql.php b/tbl_sql.php index 5565d923b..f3c3aac6e 100644 --- a/tbl_sql.php +++ b/tbl_sql.php @@ -38,7 +38,7 @@ require_once './libraries/tbl_links.inc.php'; /** * Query box, bookmark, insert data from textfile */ -PMA_sqlQueryForm(true, false, isset($_REQUEST['delimiter']) ? $_REQUEST['delimiter'] : ';'); +PMA_sqlQueryForm(true, false, isset($_REQUEST['delimiter']) ? htmlspecialchars($_REQUEST['delimiter']) : ';'); /** * Displays the footer