62个理由让你解雇你的超级管理员
在我们上一期中,我们讨论了任何Joomla!网站都属于同质化人群,为什么从安全角度来看这很糟糕,以及如何通过更改数据库表前缀来避免这种情况。在本期中,我们将进一步扩展,确保另一组常见的特性——超级管理员用户名和ID——与潜在黑客预期的不同。
那个叫“62”的家伙是谁呢?
一旦安装了Joomla!,潜在的黑客就已经对你网站的设置了解得太多。你有一个超级管理员用户,他的ID是62。他的用户名是admin。唯一缺失的“拥有”你网站的关键信息是你的密码。如果黑客发现你网站上存在一个易受攻击的扩展,这个密码可能会被窃取或更改。你看,已知的常数是一个安全噩梦,正如在针对Joomla! 1.5.5的攻击中所清楚展示的,该攻击导致许多网站被破坏,因为发现漏洞的研究人员在没有Joomla!团队有机会修复它之前就将其发布给了公众。记住,属于同质化人群对你的健康可能非常糟糕!
一个简单的解决方案是将这个知名用户账户降级到注册用户级别并阻止它,让潜在的黑客无处可逃。然而,为了完成我们的安全修改,我们确实需要另一个超级管理员。问题是,如果你只是创建一个新用户,他的ID将是63,这根本不安全;这是黑客的第二好选择。因此,我们需要一种方法来创建一个具有随机ID的超级管理员,最好是1-61范围内的,这个范围在Joomla!中尚未使用。这就是我们将要做的,只需三个SQL命令。
警告:如果您遵循本文中的建议,您将修改您网站的数据库。尽管以下程序已经过充分测试,但最好先在本地测试服务器上练习。在任何情况下,都不要在没有有效、经过测试的备份的情况下尝试将这些操作应用于实时网站!
窥探Joomla!的用户管理内部
Joomla! 1.5 使用两种紧密集成的机制来验证用户身份。首先,我们有存储在 jos_users 表中的数据。它包括用户名、密码以及用户所属的组。关于这个表有一些重要的信息。首先,所有用户ID从62开始计数。用户ID 1-61是空闲的,不能通过后端分配。然后,密码以 md5:salt 格式存储。盐是一个随机字符串。md5部分是密码和盐的MD5哈希值。所以,对于盐字符串 "abcd" 和密码 "foobar",我们需要计算 "foobarabcd" 的MD5哈希值。这个计算可以通过 在线MD5计算 来完成,结果为 9aa618c6255a7259d747113d7e649925。因此,密码字段将是 "9aa618c6255a7259d747113d7e649925:abcd"。这意味着我们可以通过分配小于62的用户ID来创建我们喜欢的用户名/密码组合。
当然,这不足以登录Joomla!它还使用的是phpGACL的简化版本。简而言之,这个机制允许使用访问控制列表,将用户视为“访问请求对象”(AROs),并将他们能做什么视为“访问控制对象”(ACOs)。这可能有点超出你的理解范围,但总体概念是,如果用户没有被标记为有权访问他应加入的组,他将无法登录网站。根据你需要了解的,每个用户映射到单个ARO,每个ARO映射到一个或多个组。如果 jos_users 表中分配的用户组与 ARO-组映射中规定的组不一致,你将无法登录。
你可能已经猜到了,但这种机制并非在数据库级别上无懈可击。首先,映射用户到ARO的表(jos_core_acl_aro)的ID从10开始。这允许我们插入ID为1-9的行,而不用担心意外地禁用其他用户的登录能力。另一个涉及的数据库表(jos_core_acl_groups_aro_map),它将ARO映射到组,是一个简单的多对多关系的粘合数组——它包含ARO和组的ID——很容易附加。
我们准备好了手术!
了解这些信息很好,但将其付诸实践则更好。比如说,我们想要创建一个名为 "hacker" 的新超级管理员用户,密码也是 "hacker",只通过数据库操作来实现,即不使用Joomla!后端界面。如果你阅读了前面的三个段落,你可能已经知道如何做了:我们只需要运行三个SQL命令。我们将关注这些命令是什么以及一个简单的方式来执行它们。我将假设你使用的是默认前缀 jos_。如果不是——如果你正在阅读这一系列安全文章,你不应该——请将 jos_ 替换为你的站点前缀。你可以使用合适的工具,如phpMyAdmin,在你的Joomla!站点数据库上执行所有这些命令。
第一个SQL命令将创建Joomla!用户,如下所示
REPLACE INTO `jos_users` (`id`, `name`, `username`, `email`, `password`, `usertype`, `block`, `sendEmail`, `gid`, `registerDate`, `lastvisitDate`, `activation`, `params`) VALUES ('60', 'T. Hacker', 'hacker',This email address is being protected from spambots. You need JavaScript enabled to view it. ', '18b42a5df78808abca92bc021a191991:abcdefghijklmnopqrstuvwxyz012345', 'Super Administrator', '0', '0', '25', '2000-01-01 00:00:00', '0000-00-00 00:00:00', '', '');
这创建了一个ID为60的用户,他的名字设置为 "T. Hacker"。请注意,密码计算遵循前面章节中概述的方案。现在,我们将构建下一个SQL命令,该命令创建一个由Joomla!用户组成的ARO对象
REPLACE INTO `jos_core_acl_aro` (`id`, `section_value`, `value`, `order_value`, `name`, `hidden`) VALUES ('8', 'users', '60', '0', 'T. Hacker', '0');
这创建了一个ID为8的ARO对象。请注意,'name'字段必须与 jos_users条目中的 'name' 字段匹配!接下来,我们将把这个ARO对象映射到超级管理员组,其组ID为25
REPLACE INTO `jos_core_acl_groups_aro_map` (`group_id`, `section_value`, `aro_id`) VALUES ('25', '', '8');
您做到了!用户现在活跃且准备登录。如果您想知道为什么我使用REPLACE而不是INSERT,那是因为我不希望查询在数据库记录已存在时失败。如果您的MySQL版本不喜欢REPLACE命令,您随时可以将其更改为INSERT!
总结操作
这是过程中最简单的一部分。既然您以新超级管理员身份登录到自己的网站,您可以访问Joomla!的用户管理页面。首先,将旧超级管理员降级到注册用户级别并点击保存。然后,再次编辑,将“锁定”设置为“是”并再次保存。您的旧超级管理员用户已经失去了权限,现在已被锁定,因此没有人可以使用它登录到您的网站。
许多人会争辩说,如果我们只是更改用户的ID而不是创建一个全新的账户,那就更好了,就像在这篇Bodvoc的博客文章中所展示的那样。这种方法对于全新网站来说效果很好。但是,如果您的网站已经有内容,这样做将会导致所有之前由用户62拥有的内容项都成为孤儿。修复所有这些记录在所有已安装组件中是一项艰巨的任务。因此,一次性创建一个具有定制用户ID的新用户、禁用旧用户、保持内容关联并提高您网站的安全性要容易得多。
那么Joomla! 1.6呢?
Joomla! 1.6在用户管理方面有一些开创性的变化。首先,默认超级管理员的用户ID变成了...42。别开玩笑,我想这确实是一种惩罚。然而,最大的单步进步是Joomla!摆脱了从Mambo时代带来的所有phpGACL遗留问题,并实现了自己的ACL系统。尽管它边缘仍然有点粗糙,但一旦它被抛光并准备好大规模消费,它将是一个重大的进步。
新ACL系统的一个非常积极的改变是,用户和组的关系不再分散在多个重叠的表中,而是干净地限制在#__user_usergroup_map表中,就像它们应该一直那样。这要求我们更改SQL命令。首先,创建新超级管理员的命令应使用小于42的ID - 比如40 - 并需要将usertype字段设置为'deprecated'或任何其他值,因为它不再使用
REPLACE INTO `jos_users` (`id`, `name`, `username`, `email`, `password`, `usertype`, `block`, `sendEmail`, `gid`, `registerDate`, `lastvisitDate`, `activation`, `params`) VALUES ('40', 'T. Hacker', 'hacker',This email address is being protected from spambots. You need JavaScript enabled to view it. ', '18b42a5df78808abca92bc021a191991:abcdefghijklmnopqrstuvwxyz012345', 'deprecated', '0', '0', '25', '2000-01-01 00:00:00', '0000-00-00 00:00:00', '', '');
这意味着一旦我们创建了上述第一个INSERT语句中的用户,我们只需要将他分配到超级管理员组
INSERT INTO `jos_user_usergroup_map` (`user_id`,`group_id`) VALUES('40','8');
正如您所看到的,这极大地减少了我们创建新超级管理员所需的工作。太棒了!
请给我一个。
哦,我知道在你告诉我之前。玩弄SQL真的很无聊,并可能导致您的网站崩溃。当这篇文章的第一版发表在我的个人博客上时,一些人SQL命令出错,无意中将自己锁在了网站上。别担心,朋友们!就像我在我上篇文章中所做的那样,我创建了一个小型的PHP脚本来帮助您。下面是
<?php
$user_id = ''; // Give a numeric user ID, or leave blank for a random one
require_once 'configuration.php';
$config = new JConfig;
$con = mysql_connect($config->host, $config->user, $config->password);
if(!is_resource($con)) die('Error connecting to db');
$test = mysql_select_db($config->db, $con);
if($test===false) die('Error connecting to db');
$prefix = $config->dbprefix;
$sql = "show tables where 'Tables_in_{$config->db}' like '{$prefix}user_usergroup_map'";
$res = mysql_query($sql);
$joomla16 = mysql_num_rows($res) > 0;
mysql_free_result($res);
if(empty($user_id)) $user_id = rand(1, ($joomla16 ? 41 : 61));
$sql = "select * from {$prefix}users where 'id' = ".($joomla16 ? 42 : 62);
$res = mysql_query($sql); $row = mysql_fetch_assoc($res);
mysql_free_result($res); $row['id'] = $user_id;
$sql = "REPLACE INTO {$prefix}users VALUES(";
$q = array(); foreach($row as $k => $v) { $q[] = "'".mysql_real_escape_string((string)$v, $con)."'"; }
$sql .= implode(',',$q).')';
mysql_query($sql) or die(mysql_error());
if($joomla16){
$sql = "INSERT INTO {$prefix}user_usergroup_map ('user_id','group_id') VALUES ('$user_id','8')";
mysql_query($sql) or die(mysql_error());
} else { $name = mysql_real_escape_string($row['name'], $con);
$sql = "INSERT INTO {$prefix}core_acl_aro ('section_value','value','order_value','name','hidden') VALUES ('users', '$user_id', '0', '$name', '0')";
mysql_query($sql) or die(mysql_error());
$aro_id = mysql_insert_id($con);
$sql = "INSERT INTO {$prefix}core_acl_groups_aro_map ('group_id', 'section_value', 'aro_id') VALUES ('25', '', '$aro_id')";
mysql_query($sql) or die(mysql_error()); }
$uname = uniqid('defsa',true); $salt = md5(microtime(false));
$pword = md5(uniqid('',true).$salt).':'.$salt;
$sql = "UPDATE {$prefix}users SET 'username' = '$uname', 'password' = '$pword', 'email' =This email address is being protected from spambots. You need JavaScript enabled to view it. ', 'block' = 1, 'sendEmail' = 0";
mysql_close($con); echo "OK";
@unlink(__FILE__);
手头的任务几乎是微不足道的。它将您的现有超级管理员用户赋予一个新的ID,同时给旧用户一个随机的用户名和密码并禁用它。您需要做的就是将这个文件放入一个文件中,命名为superadmin.php,上传到您的网站,并通过浏览器调用它,例如http://www.yoursite.com/superadmin.php.就这样!
我还有一些想法,但是...
...再次,我的空间用完了!不管怎样,如果您从一开始就阅读了这个系列的每一篇,并遵循了我的所有建议,那么您现在对安全有了更深的理解,并且已经采取了基本步骤来保护您的网站。在下一期中,我们将继续讨论我在过去十二个月中一直在研究和调整的一系列黑客预防规则和“伪装”规则。
下次见,保重,安全第一!
《Joomla社区杂志》上发布的一些文章代表了作者对特定主题的个人观点或经验,可能并不代表Joomla项目官方立场。
通过接受,您将访问由https://magazine.joomla.net.cn/之外的第三方提供的服务
评论