The Joomla! ® Community Magazine

62 reasons to fire your Super Administrator

Written by | Wednesday, 01 September 2010 00:01 | Published in 2010 September
Level of Difficulty:Intermediate In our last issue we were discussing about how any Joomla! site belongs to a homogeneous population, why this is bad from a security perspective, and how to avoid that by changing your database table prefix. In this issue, we are going to expand a bit more, by making sure that another set of common characteristics – the Super Administrator user name and ID – are different than those a potential hacker would expect.

Who’s that bloke called “62”, anyway?

As soon as you install Joomla!, a potential hacker already knows too much about your site's set-up. You have a Super Administrator user and his ID is 62. His user-name is admin. The only key information missing for “owning” your site is your password. This can be stolen or changed if the hacker finds a vulnerable extension on your site. You see, known constants are a security nightmare as made clear in the case of the attack against Joomla! 1.5.5, which caused a lot of sites to be compromised as the researcher who found the vulnerability released it to the general public before the Joomla! team had a chance to fix it. Remember, belonging to a homogeneous population can be very bad for your well-being!

One easy workaround is to demote this well-known user account down to the Registered level and block it, hanging potential hackers to dry. However, in order to complete our security modification we do need another Super Administrator. The problem is that if you just create a new user his ID will be 63, which is not secure at all; it's a hacker's next best bet. So, we need a way to create a Super Administrator with a random ID, preferably in the 1-61 range which is otherwise unused in Joomla!. This is what we are going to do, with just three SQL commands.

WARNING: If you follow the advice in this article, you will be modifying your site's database. Even though the following procedure is well-tested, it's best to practice it on a local testing server first. Never, ever and under no circumstances try to apply these on a live site without a valid, tested backup!

Peeking at Joomla!'s user management underbelly

Joomla! 1.5 uses two tightly integrated mechanisms for authenticating users. For starters, we have the data stored in the jos_users table. It's the user-name, password and the group where the user belongs. There are some important pieces of information about this table. To begin with, all user ID's begin counting from 62. User IDs 1-61 are free and can't be assigned using the back-end. Then, the password is stored in the format md5:salt. Salt is a random string. The md5 part is the MD5 hash of the password and the salt. So, for a salt string "abcd" and a password "foobar", we have to calculate the MD5 hash of "foobarabcd". This calculation is easy to perform with an on-line MD5 calculation and results to 9aa618c6255a7259d747113d7e649925. So, the password field would be "9aa618c6255a7259d747113d7e649925:abcd". This means that we can create a user-name/password combination of our liking by assigning it a user ID less than 62.

Of course, this is not enough to log in to Joomla!. The other mechanism it uses is a cut-down version of phpGACL. In short, this mechanism allows the use of Access Control Lists which treats users as "Access Request Objects" (AROs) and what they can do as "Access Control Objects" (ACOs). This might be a bit over your head, but the overall concept is that if the user isn't marked as having access to the group he's supposed to be part of, he won't be able to login to the site. For all you need to know, each user is mapped to a single ARO and each ARO is mapped to one or more groups. If the user group assigned in the jos_users table is not in accordance to the group prescribed in the ARO-group mapping, you can't log in.

You might have guessed it, but this mechanism is not fool proof down to the database level. First off, the table which maps users to AROs (jos_core_acl_aro) has its IDs start from 10. This allows us to insert rows with IDs 1-9 without the fear of accidentally disabling another user's login ability. The other database table involved (jos_core_acl_groups_aro_map), which maps AROs to groups, is a simple glue array of a regular many-to-many relationship - it holds IDs of both ARO and group - is easy to append to.

We're ready for surgery!

Having this insight is good, but putting it to real use is even better. Let's say that we want to create a new Super Administrator user called "hacker", with a password of "hacker", using nothing but database manipulation, i.e. without using the Joomla! back-end interface. If you read the previous three paragraphs you might have figured out how: we just need to run three SQL commands. We'll focus on what these commands are and an easy way to deliver them. I will assume that you are using the default prefix jos_ for the following examples. If you're not – and you shouldn't if you're reading this series of security articles – please substitute jos_ with your site's prefix. You can execute all these commands against your Joomla! site's database using a suitable tool, such as phpMyAdmin.

The first SQL command will create the Joomla! user and looks like this:

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', '', '');

This creates a user with ID 60 and his name set to "T. Hacker". Do note the password calculation which follows the scheme outlined in the previous section. Now, we'll craft our next SQL command which creates an ARO object out of the Joomla! user:

REPLACE INTO `jos_core_acl_aro` (`id`, `section_value`, `value`, `order_value`, `name`, `hidden`) VALUES ('8', 'users', '60', '0', 'T. Hacker', '0');

This created an ARO object with ID 8. Do note that the 'name' field must match the 'name' field of the jos_users entry! Next up, we'll map this ARO object to the Super Administrator group, which goes by the group ID 25:

REPLACE INTO `jos_core_acl_groups_aro_map` (`group_id`, `section_value`, `aro_id`) VALUES ('25', '', '8');

There you go! The user is active and ready for login. If you're wondering why I use REPLACE instead of INSERT, well, it's simply because I wouldn't like the query to fail if the database record already exists. If your MySQL version doesn't like the REPLACE commands, feel free to change them to INSERTs at any time!

Wrapping up the operation

This is the easiest part of the process. As you are logged in as the new Super Administrator to your own site, you can go to Joomla!'s Users Manager page. First, demote the old Super Administrator down to the Registered level and click on Save. Then, edit again, set "Block" to "Yes" and save again. Your old Super Administrator user has lost his privileges and is now locked so that nobody can use it to log in to your site.

Many people would argue that we would be better off if we simply changed the user's ID instead of creating a brand new account, as demonstrated in this Bodvoc's blog post. This approach works well if you have a brand new site. But if your site already has content, doing so would leave all content items previously owned by user 62 orphans. Fixing all such records in all installed components is a mighty task. Ergo, it's much easier creating a new user with a bespoke user ID and disabling the old user, keeping content association and increasing your site's security in a single go.

What about Joomla! 1.6?

Joomla! 1.6 has some ground-breaking changes in the user management. First off, the default Super Administrator's user ID became... 42. No kidding and I guess there is a pun intended. The single major step, however, is that Joomla! got rid of all the phpGACL legacy it was carrying from the Mambo era and implements an ACL system of its own. Even though it's still a bit rough on the edges, it will be a major step forward once it is polished and ready for mass consumption.

The very positive change with the new ACL system is that user and group relationships are no longer spread across multiple overlapping tables, but neatly confined in the #__user_usergroup_map table, in the way they should have always been. This calls for a change in our SQL commands. First, the command to create the new Super Administrator should use an ID lower than 42 – let's say 40 – and needs to set the usertype field to 'deprecated', or any other value as it's no longer used:

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', '', '');

This means that once we have created a user with the first INSERT statement above, all we have to do is assign him to the Super Administrator group:

INSERT INTO `jos_user_usergroup_map` (`user_id`,`group_id`) VALUES('40','8');

As you can see, this greatly reduces the work we have to go through to create a new Super Administrator. Splendid!

Can I have one to go, please?

Oh, I know before you tell me. Fiddling with SQL is seriously not fun and bound to break your site. When the first version of this article was put up on my personal blog, a few people got their SQL commands wrong and inadvertently locked themselves out of their sites. Fear not, my friends! Just like I did with my last article, I've created a smallish PHP script to help you out. Here we go:

<?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__);

The task at hand is almost trivial. It will take your existing Super Admin user and give it a new ID, while giving the old user a random username and password and disabling it. All you have to do is put this in a file, name it superadmin.php, upload it to your site and call it from your browser, e.g. http://www.yoursite.com/superadmin.php. That's all!

I still have some ideas, but...

...once more, I've run out of space! Anyway, if you've read this series from the very beginning and followed all of my advice, you now have a strong grip on security, and have already taken the basic steps to protect your site. In the next issue we'll continue our discussion with a set of hacking prevention and “cloaking” rules I've been working on and tweaking for the last twelve months.

Until next time, take care and be safe!

Read 51847 times
Tagged under Administrators
Nicholas K. Dionysopoulos

Nicholas K. Dionysopoulos

A Mechanical Engineer turned web developer I am mostly known as the lead developer of Akeeba Backup, the leading open source backup solution for Joomla!. When not working on my flagship software I enjoy squashing Joomla!bugs, writing articles about Joomla!, helping out with this magazine and playing the guitar.

Leave a comment

Make sure you enter the (*) required information where indicated.

[b] [i] [u] [s] [url] [quote] [code] [img]   

Comments (23)

  • avatar
    • 0
    • 0
    Galo Mayorga - Turbos Ecuador

    That's a really great article.

    However, for newbies like me is a kind of difficult to implement this type of solutions... But I have to learn.

    Thank you

  • avatar
    • 0
    • 0
    Paulus

    Maybe we should get the option to give ourselves a random username AND password during installation?....not sure why a new Joomla installation is not secure and downright hackable by default....

    If you designed a customer's website that way; why would they pay you?

  • avatar
    • 0
    • 0
    Polly Marzahl

    I got the same error as stated above:
    'Column count doesn't match value count at row 1'

    I agree with everyone else though - these are great articles! Just wish I could get the script to work:(

  • avatar
    • 0
    • 0
    Parvez

    Great Article Nicholas!
    Thank you so much.

  • avatar
    • 0
    • 0
    Anupam Chatterjee

    I tried to execute the entire script as provided by you above.

    However, I got the following error:
    "Column count doesn't match value count at row 1"

    Could you enlighten me on what I did incorrectly?
    Thanks

  • avatar
    • 0
    • 0
    Jordan

    Great post

    But I must be missing something...

    For existing sites with many users already and a superadmin with ID 62, why not simply demote the old user after creating a new one rather than block. This way in social network or forum sites, that user will still the reachable. As well creating a super admin and demoting the old could all be done with Joomla backend and no database changes.

  • avatar
    • 0
    • 0
    VJ

    @ Jordan: "for existing sites with many users" - key word is many users. So if you have 500 users from 62-562 anyone can be a super admin; that's cool and the above is not necessary.

    But this guide's for a single user joomla install or maybe 4-5 users where user ID's are predictable.

    Nicholas K - you are the man. Awesome guide. I always wondered that if I created a new user he'd be 63, so predictable - but you've cleared up that misconception.

    I am eagerly awaiting October for the next issue.

  • avatar
    • 0
    • 0
    Rich

    First try resulted in:

    Column count doesn't match value count at row 1

  • avatar
    • 0
    • 0
    Freedom OSS

    Nicolas you're great! That's why I bought your product Akeeba Backup Pro without hesitation.

    Thanks for the nice and helpful article. Can't wait to read your next item on J! security.

    Regards,

  • avatar
    • 0
    • 0
    leo lammerink

    Good article Nicholas. Might be little hefty for inexperienced users though?

    An script exists that does this the easy way and it works: changes the admin and admin id

    Change Super Admin

    http://extensions.joomla.org/extensions/tools/site-management-tools/12149?

  • avatar
    • 0
    • 0
    Nirmal

    I got one confusion on changing super admin. I've posted many articles in my blog from that 62 id. If i delete that id and create new one, what will happen to these post and activities?

  • avatar
    • 0
    • 0
    Slavi H

    Thanks man! Very helpful!

  • avatar
    • 0
    • 0
    Jeejee

    enter your message here...

    Rich wrote:
    First try resulted in:

    Column count doesn't match value count at row 1

    The script does the same for me... What could be the problem?

  • avatar
    • 0
    • 0
    Nicholas K. Dionysopoulos

    For some odd reason I can not get script rendered correctly on this site. The way it was cut off makes it compatible only w/ Joomla! 1.6. You can always try running the SQL commands presented in the article manually.

  • avatar
    • 0
    • 0
    JD

    Good stuff! I have not tested it yet but I just want to know, whether:

    1. The password of the newly created user can be changed normally from the back-end?

    2. Whether subsequent Super Admins created from the back-end will have user ID's starting from 41 (or the next available number above the one used in the query)?

    Thanks

  • avatar
    • 0
    • 0
    Rich

    Okay, so I finally realized that the "One to Go" script is for Joomla 1.6. But the three snippets worked beautifully on 1.5.21!

  • avatar
    • 0
    • 0
    chay

    Another wonderfully helpful article! Many thanks.

  • avatar
    • 0
    • 0
    John Coyne

    A truly interesting and very practical article on Joomla security. The SQL code you generously provided is the icing on the cake (and worked beautifully.) Looking forward to reading more articles from you in future Nicholas. :)

    Best
    John

  • avatar
    • 0
    • 0
    JD-Webdesign

    Hi,

    What's the behavior of the superadmin.php script when you have 2 super administrators for example ?

    Is the script works for both ?

    Thanks,

    JD

  • avatar
    • 0
    • 0
    steve

    I have just changed my Admin from 62 to a high 600 odd number.

    that was before I read the above article, is there any reason why best between 1-60 and will mine cause any problems.

    thanks

  • avatar
    • 0
    • 0
    dipendra

    i really apperciate your sharing i was looking for this info long time ago

  • avatar
    • 0
    • 0
    Gabriel Serna

    I delete by mistake the user with ID 42

    The problem:

    I recently migrate my website from Joomla 1.5 to Joomla 1.7, i do it by my self but i made a mistake after the migration was finished.

    The mistake was that i delete from the new database the user with ID 42 because i didn´t know that in Joomla 1.7 this was the principal ID for the Super User, and i thought that if i already have my own super administrator with id 62 (from my old website) i will no longer need the new user 42... it was terrible, because i didn´t know all the problems that will came with it.

    When i saw the problems (always login and logout the super administrators in the frontend, every time that i change from one article to another) i tryed to restore the super user adding manually the id and user again in my database. But i guess is more complicate than that... Today my website is running because i can´t stop the service, but the same problem persist, every time i´m loged as a super user in the frontend and if i change the page to another article or section or component, the login module and the online users module, show me as if i was un loged. I thought there is more, but untill now that is the principal bug... My question is:

    What is the best way to recover the user 42 as a principal Super User and fnally solve this problem?

    What do you recommend me to do?

    I have 4000 users,
    3000 articles
    and at least 5 components as Kunena, and Jomsocial.

    Thank you very much... i hope you can help me.

Language Switcher

Grab the Joomla! Community Banners! Spread the word!

Recommend us on Google+