Futurama Quotes WordPress Plugin

Posted by Ryan Uber | PHP | Sunday 14 November 2010 1:11 pm

Futurama has been one of my favorite TV shows for years now. Lately I’ve had a bit of spare time on my hands now that standard time is here again. It’s dark long before I get home from work, so I recently went through a pretty good chunk of the Futurama episodes I have. It brought back some very fond memories.

You know that “Hello Dolly” plugin that always comes with wordpress? The one you never enable? Well I thought it handy as a framework for the plugin I decided to make: Futurama Quotes! This plugin is stupid-simple. There is nothing to it, just an array of quotes that I snagged from the internet and made HTML-friendly, a little CSS, and a randomizer. The result I think was worth it:

This zip file contains just one php script that will add this functionality to your blog. The text will only show up in your admin portal (not on public-facing pages).

Download:
Futurama_Quotes_1.0

osCommerce password hashing function concept

Posted by Ryan Uber | PHP,Security | Friday 24 September 2010 11:57 am

I had the sincere displeasure of troubleshooting an osCommerce site this morning. The user had lost their password, so naturally, I had to generate them a new one. I found their password hashing function burried in the “admin/includes/functions/password_funcs.php” script:

  function tep_encrypt_password($plain) {
    $password = '';

    for ($i=0; $i<10; $i++) {
      $password .= tep_rand();
    }

    $salt = substr(md5($password), 0, 2);

    $password = md5($salt . $plain) . ':' . $salt;

    return $password;
  }

Now then, I had a quick look in the database itself, at the “admin” table:

mysql> select * from administrators;
+----+-----------+-------------------------------------+
| id | user_name | user_password                       |
+----+-----------+-------------------------------------+
|  1 | admin     | 60a272d8be550ff714cf6bb385531d3a:6b |
+----+-----------+-------------------------------------+
1 row in set (0.00 sec)

Hmmm…. so its not a plain MD5sum. I was interested to see what they were doing beyond just MD5′ing the password so I actually went through what the code is doing.

Firstly, we call the function and pass it a plain-text password to encrypt:

tep_encrypt_password($plain)

Then, we are defining a variable called “$password” a random 10-character string:

    for ($i=0; $i<10; $i++) {
      $password .= tep_rand();
    }

Let’s just stop right there for a minute. We have two variables already: “$plain” and “$password”. The one called “plain” is actually the plain-text password, and the one called “password” is a random string. Excellent variable naming, osCommerce.

Moving on, we then use the random string, also known as “$password”, to get the “salt” for the password:

$salt = substr(md5($password), 0, 2);

Now let’s stop right there. A two-character salt? Essentially, this is just md5′ing the already-random “$password” variable, and snagging the first two characters of it.

Next, we do some flippity-floppying with variables:

    $password = md5($salt . $plain) . ':' . $salt;

The above is going to append the plain-text password to the two-character “salt” and MD5 it, the append a colon (:) character, then append the plain-text “salt” to the end of the string. The colon will likely be used for a preg_split or similar in a password checking function. What bugs me about the above code though, is that now we are reassigning the variable “$password” to the actual encrypted / salted version of the plain text password, rather than it just containing arbitrary characters as it did before.

Then we return the newly-encrypted password:

return $password;

That bugs me too, because we are not returning a password, we are returning an encrypted hash with a salt tailing it.

This is all a bunch of nit-picking, and the code actually does what it is supposed to do, but it is a big pet-peeve of mine because it makes the code a lot harder to follow, even due to something so small as a variable name.

Another thought, this actually does prove helpful to security of encrypted password storage. Of course anyone on the outside could still hit your login form 6 million times with their dictionary of commonly-used passwords, and if one matched they would be in. However, it does help in preventing someone who has obtained the hash from getting the actual password value from it. You wouldn’t be able to run osCommerce’s password hashes through an MD5 lookup and get passwords out of it.

So in conclusion, I might be too critical on the syntax, but this password encryption function actually does a decent job. I’d recommend doing something similar the next time you write a PHP application before just doing “INSERT INTO users ( $user_name, MD5($password);”.

Basic Server Statistics Script

Posted by Ryan Uber | Apache,Linux,Performance,PHP | Saturday 4 September 2010 12:21 pm

Recently at work, I found myself needing to give a customer access to a few basic statistics on his web servers, but seeing as they are 100% managed, and they get no type of access other than FTP, I had to find a way to deliver them the numbers they wanted by means other than SSH.

FTP would not be a good candidate, it doesn’t make sense that they would need to FTP down a file with stats information every time they wanted to check it out. I decided to “KISS” (keep it simple / stupid) and wrote the following PHP script to get the job done:

<?php
/* Codero Dedicated Support Team <dedicatedsupport@codero.com>
 *
 * File Name: get_server_stats.php
 * Author:    Ryan R. Uber <ryanu@codero.com>
 *
 * Provides an easy http-accessible script to display commonly needed
 * server statics information.
 *
 * Note: Enable exec() to get Apache connection stats.
 * Run:  echo -n "PASSWORD HERE" | md5sum
 *       to generate a password
 */

# Authentication Definitions
$useAuth = false;
$authMD5 = 'Paste generated MD5SUM here';

# Perform login
if ( $useAuth === true )
{
    session_start();

    if ( $_SERVER['REQUEST_METHOD'] == "POST" )
    {
        if ( md5 ( $_POST['password'] ) == $authMD5 )
        {
            $_SESSION['loggedIn'] = 'true';
        }
    }

    # Prompt for password
    if ( ! isset ( $_SESSION['loggedIn'] ) )
    {
?>
<form action=<?=$_SERVER['PHP_SELF']?> method=POST>
<font size=5>Authentication required</font><br>
<font size=2><b><i>Password: </b></i><input type=password name=password><br>
<input type=submit value="Authenticate">
</form>
<?php
        die();
    }
}

# Initialize Variables
$hostname           = $_SERVER['HTTP_HOST'];
$unique             = array();
$www_unique_count   = 0;
$www_total_count    = 0;
$proc_count         = 0;
$display_www        = false;

# Check if 'exec()' is enabled
if ( function_exists ( 'exec' ) )
{
    $display_www = true;

    # Get HTTP connections
    @exec ( 'netstat -an | egrep \':80|:443\' | awk \'{print $5}\' | grep -v \':::\*\' |  grep -v \'0.0.0.0\'', $results );
    foreach ( $results as $result )
    {
        $array = explode ( ':', $result );
        $www_total_count ++;

        if ( preg_match ( '/^::/', $result ) )
        {
            $ipaddr = $array[3];
        }

        else
        {
            $ipaddr = $array[0];
        }

        if ( ! in_array ( $ipaddr, $unique ) )
        {
            $unique[] = $ipaddr;
            $www_unique_count ++;
        }
    }
    unset ( $results );
}

# Get Server Load
$loadavg = explode ( ' ', file_get_contents ( '/proc/loadavg' ) );
$loadavg = "{$loadavg[0]} {$loadavg[1]} {$loadavg[2]}";

# Get Disk Utilization
$disktotal = disk_total_space ( '/' );
$diskfree  = disk_free_space  ( '/' );
$diskuse   = round ( 100 - ( ( $diskfree / $disktotal ) * 100 ) ) . "%";

# Get server uptime
$uptime = floor ( preg_replace ( '/\.[0-9]+/', '', file_get_contents ( '/proc/uptime' ) ) / 86400 );

# Get kernel version
$kernel = explode ( ' ', file_get_contents ( '/proc/version' ) );
$kernel = $kernel[2];

# Get number of processes
$dh = opendir ( '/proc' );
while ( $dir = readdir ( $dh ) )
{
    if ( is_dir ( '/proc/' . $dir ) )
    {
        if ( preg_match ( '/^[0-9]+$/', $dir ) )
        {
            $proc_count ++;
        }
    }
}

# Get memory usage
foreach ( file ( '/proc/meminfo' ) as $result )
{
    $array = explode ( ':', str_replace ( ' ', '', $result ) );
    $value = preg_replace ( '/kb/i', '', $array[1] );
    if ( preg_match ( '/^MemTotal/', $result ) )
    {
        $totalmem = $value;
    }

    elseif ( preg_match ( '/^MemFree/', $result ) )
    {
        $freemem = $value;
    }

    elseif ( preg_match ( '/^Buffers/', $result ) )
    {
        $buffers = $value;
    }

    elseif ( preg_match ( '/^Cached/', $result ) )
    {
        $cached = $value;
    }

}
$freemem = ( $freemem + $buffers + $cached );
$usedmem = round ( 100 - ( ( $freemem / $totalmem ) * 100 )  ) . "%";
?>

<html>
<body>
<font size=5><b><?=$hostname?></b></font><br><br>
<?php
if ( $display_www === true )
{
?>
<font size=4><b>Web Server (80 and 443)</b></font><br>
<font size=3><b><i><?=$www_unique_count?></b></i></font><font size=2> unique connections</font><br>
<font size=3><b><i><?=$www_total_count?></b></i></font><font size=2> total connections</font><br>
<?php
}
?>
<font size=3><i><b>Kernel Version:</b> <?=$kernel?></i></font><br>
<font size=3><i><b>Uptime:</b> <?=$uptime?> days</i></font><br>
<font size=3><i><b>Load Average:</b> <?=$loadavg?></i></font><br>
<font size=3><i><b>Disk Use:</b> <?=$diskuse?></i></font><br>
<font size=3><i><b>Memory Utilization: </b><?=$usedmem?></i></font><br>
<font size=3><i><b>Total Processes: </b><?=$proc_count?></i></font><br>
</body>
</html>

How do I use it?
Just place the above script anywhere in an Apache-servable directory with libphp5 loaded. I attempted to make as much of the script “exec-free” as possible, so currently you only need to configure the exec() function (as mentioned in the script header) if you want to be able to see the number of connections to the Apache webserver. I’m assuming that you have this turned off on your web server, although the PHP default .ini leaves it enabled.

Authentication
This script has a small built in “wanna-be” authentication mechanism. If you want to require a password for a viewer to see this valuable information, all you would need to do is set the “useAuth” variable to “true”, and paste in an md5-hash for the password. I didn’t both with a user for this script.

Get the MD5 password:

$ echo -n 'soooooooSecure' | md5sum

Configure the script:

$useAuth = true;
$authMD5 = "[paste the md5 from the above command here]";

Alternate password method
You can also use a .htaccess file or similar if you want to have multiple users and passwords. Simply disable authentication in the script, and continue on your way with the htpasswd command.

$useAuth = false;
« Previous PageNext Page »