- Designed and built filter management system, focused on handling individual Exim filtration commands
- Must use SquirrelMail's login ID to prevent multiple requests for usernames and passwords
- SquirrelMail needs to have a link to the filter management system
The Filter Management System requires a username and a password, in order to properly ensure the user is who they say they are. To integrate the security of SquirrelMail into the FMS, we must identify the methods SquirrelMail uses to store and retrieve passwords for authentication purposes.
This requires a trace of the SquirrelMail code to identify the interface mechanism.
Once the identity has been obtained, we develop a solution for integrating this identity into the FMS software, and properly add this to the
add.pm package.
Once the solution is integrated, the templates/links for editing the filters need to be altered in SquirrelMail to link to the FMS software.
Method Notes on Obtaining the Password
Prior to entering the starting point, we must know what we need to watch for. For example, in dismantling unix password data, we keep our eyes open for the
crypt() function, as it is an integral part of understanding how the software works.
Performing research (
web research) on SquirrelMail login processes fails to reveal any information as to what we need to look for. This project begins with the research into login problems and issues rather than processes, as bugs should be publicly available, and will almost always provide a starting point for debugging the process. Beginning here, we learn that prior to php4.1, SquirrelMail used
HTTP_SESSION_VARS variables to hold login information, and after 4.1 should have used
session_register to set these variables. On doing a grep for
session_register, we find nothing. Reducing the grep term to
register, we reveal that most variable calls to
sqsession_register.
Once we know what we are watching for, we begin to trace down where the passwords are stored, and how we access them. This must begin at the standard "login" screen. We determine where the document is by first connecting to SquirrelMail. Once we have a login screen, we examine the url to access the page, and find
http://mail.yourdomain.com/webmail/src/login.php. With this in hand, we open up a shell to the webmail server, and change into the document root of the web server configuration. For instance, you might find yourself in
/var/www/html (linux) or
/usr/local/www/data (FreeBSD).
We change into the URI portion of the url without the script name (
webmail/src/). Editing the document login.php reveals more information. The only handler in the document prints a form, containing the variables
username and
secretkey. It submits the information to
redirect.php.
When we examine the
redirect.php script, we search for
secretkey, as that is the password field we are interested in. On grep-ing through the
redirect.php, we find the following matching lines of code.
if (isset($_POST['secretkey'])) {
$secretkey = $_POST['secretkey'];
$onetimepad = OneTimePadCreate(strlen($secretkey));
$key = OneTimePadEncrypt($secretkey, $onetimepad);
With these lines, we see that a global variable is set
$secretkey, which is used in a specialized function
OneTimePadCreate.
If we open up the file itself and look at all of these instances, we find that the first two matching lines are grouped together and primarily set the global variable. The next occurances of the secretkey line use that global variable, and are also grouped together. These lines are followed by a
sqsession_register. Obviously, this is the code that stores the password we are looking for.
When we look for this
OneTimePadCreate function, we will find it in the parent directory's subdir
functions, in a file called
../functions/strings.php. This function creates a completely new string that is the same length of the password. So, this function is not the culprit, but is involved in the encryption method on the next line as the "key", and is then stored in the session information file.
So, we examine the rest of that section of code looking for a
$key variable, and find lines :
$imapConnection = sqimap_login($login_username, $key, $imapServerAddress, $imapPort, 0);
setcookie('key', $key, 0, $base_uri);
Login, and you should now have a cookie set for your web server called "key". This can be decrypted by copying the
OneTimePadDecrypt function and accessing the
OneTimePadCreate. When we examine the decryption function (also in
../functions/strings.php), we get the following code:
function OneTimePadDecrypt ($string, $epad) {
$pad = base64_decode($epad);
$encrypted = base64_decode ($string);
$decrypted = '';
for ($i = 0; $i < strlen ($encrypted); $i++) {
$decrypted .= chr (ord($encrypted[$i]) ^ ord($pad[$i]));
}
return $decrypted;
}
Now, to re-write this into perl, we must first abstract it into
pseudo-code. The resulting
pseudo-code function is :
function ([encoded password], [key])
base64 decode [key]
loop on each charatcer in [encoded password]
exclusive or it with the corresponding character in the [key]
end loop
return the resulting password
end function
Now, in perl, I thought I'd just split the incoming parameters into arrays, and then process the information. Plus, we could always use MIME::base64 to reduce our code size, but just in case you don't have access to the MIME::base64 module :
sub base64_decode {
$_[0] =~ tr#A-Za-z0-9+/##cd;
$_[0] =~ tr#A-Za-z0-9+/# -_#;
my $len = pack("c", 32 + 0.75*length($_[0]));
return unpack("u", $len . $_[0]);
}
sub decode_password {
my ($p,$k) = @_;
my @password = split(//,base64_decode($p));
my @key = split(//,base64_decode($k));
my $decrypted_password = '';
my $count = 0;
### decrypt the password
my $size = scalar(@password);
$size = scalar(@key) if (scalar(@key) < $size);
while ($count < $size) {
print "pass [$password[$count]] key [$key[$count]]\n";
$decrypted_password .= ($password[$count] ^ $key[$count]);
$count++;
}
return $decrypted_password;
}
Now, that was a keyboard full. But, for you hackers out there, that is the basic gist of decrypting the passwords.
Now we're getting somewhere. We place our function into the filter management script's
auth.pm module, and put the base64_decode function into cgi (as that's where it should be). Then, we edit the main function to check if there is a username/password submission (already there), then check the SQMSESSID variable and it's session file for the appropriate information. If that succeeds, set the username key and write the password.
This is fairly simple. Looking at the "Filter" links in the options folder will produce a url. Grep for this url, and take the most common (happens to be
plugins/filters/setup.php). In side of that script, close to the bottom, it lists some "url" fields, complete with instructions. Remove the second addition, and then alter the first to point to the FMS scripts, altering the description and control methods.
Setting up the proper integration takes time, and can be an effective method for connecting systems. With the above document, we have discussed (and implemented) solutions for controlling Exim/SquirrelMail using a third party program. The FMS software is available from
Joe Lewis, the author, and custom integrations are indeed available.