The Certificate that wouldn’t move

I have been working a lot with SSL certificates lately. The other day I had to move a certificate from Windows to Linux server, the certificate is for both www and without. It´s a simple task to export the certificate from Windows server 2012R2 and then convert the certificate so it works on Apache. Except that the CSR was done without the “Export private key” checkbox. Bummer

I thought that there must be a way to change that, after all I am Domain Administrator. Nope, there is no easy way to go around this. After a long time of googling I come over something that a thought was worth sharing.

I found a great tool! Mimikatz

http://blog.gentilkiwi.com/mimikatz

This tool can read out the key via Windows API, and a lot more!

Together with the instructions from this blog

http://blog.ruecker.fi/2014/03/12/exporting-the-not-exportable/

Download the binaries at extract the files. Start a command shell as administrator and run the 64bit version of mimikatz.exe

In the prompt just past in the following lines:

crypto::capi
crypto::certificates /systemstore=CERT_SYSTEM_STORE_LOCAL_MACHINE /export

This will export all certs on the server. The password for the exported certificates is: mimikatz

This tool can do a lot more terrifying things, for example find passwords in clear text

privilege::debug
sekurlsa::logonpasswords

WordPress version update reminder

So I have some Linux, Ubuntu, servers that are used for shared hosting. Many of the customers use WordPress and I think that it’s an awesome solution that so many can get a great website up and running in almost no time. The flaw with WordPress is that it has a lot of security holes if they don’t upgrade to the latest version. WordPress has a great update feature, but since my customers do not log in on their sites they don’t see that, so what to do. I decided that sending them an email would maybe encourage them a little, specifically the site admin.

I couldn’t find any good script that solved my problem so I decided to copy paste something that would do the trick.

Updated and locate are a good start for finding version.php.

I’ve put my files under /root/scripts/wp-version

run-wp.version-finder.sh looks like this:

updatedb
locate wp-includes/version.php | xargs grep "wp_version = " > /root/scripts/wp-version/tmp-version.txt
php /root/scripts/wp-version/wp-version.php

The wp-version.php script looks like this:

 /root/scripts/wp-version/tmp-version.txt

// curl_init and mysql is needed for this to work.
// apt-get install php5-intl

// Adminiadress, sends short summary.
$AdminAdress = "[email protected]";        // Change e-mail adress
$ServerName = "SERVER_NAME";
$Sender = "[email protected]";

$myFile = "/root/scripts/wp-version/tmp-version.txt";
$summary = "";

//check for latest WordPress version
$apiUrl = 'http://api.wordpress.org/core/version-check/1.6/';
$apiFile = 'cache/api.json';

// Verify that cache folder exist
if (!file_exists('cache')) {
    mkdir('cache', 0777, true);
}

if((is_file($apiFile) and filemtime($apiFile)< time()-3600) OR !is_file($apiFile)) {
    $apiContent = getData($apiUrl);
    if($apiContent!=''){
        file_put_contents($apiFile, $apiContent);
    }
}

$apiContent = file_get_contents($apiFile);
$apiReturn = unserialize($apiContent);
$current_version = $apiReturn['offers'][0]['current'];

$lines = file($myFile);

foreach ($lines as $line_num => $line) {
    $adminEmail = array();
    $siteAdminEmail = array();
    $wpversionArr = explode( "'", $line);
    $wpversion = $wpversionArr[1];

    // Verify against wordpress.org if the version is the latest.
    if (version_compare($wpversion, $current_version, '<')) {

        // Verify that the file wp-config.php is place.
        // There is a need to check if the file is found i one of the parent folders, future fix
        $filename = explode( "wp-includes/", $line);
        $filename = $filename[0] . "wp-config.php";

        if (file_exists($filename)) {
            $configlines = file($filename);
            $DB_USER = "";
            $DB_PASSWORD = "";
            $DB_HOST = "";
            $DB_NAME = "";
            $tbl_prefix = "";
            $siteurl = "";
            // get all the variables that is needed for mysql connection.
            foreach ($configlines as $line_num => $configline) {
                if (strpos($configline,"'DB_USER'") > 0 ) {
                    $DB_USER = (explode( "'", $configline));
                    $DB_USER = $DB_USER[3];
                }

                if (strpos($configline,"'DB_USER'") > 0 ) {
                    $DB_USER = (explode( "'", $configline));
                    $DB_USER = $DB_USER[3];
                }

                if (strpos($configline,"'DB_PASSWORD'") > 0 ) {
                    $DB_PASSWORD = (explode( "'", $configline));
                    $DB_PASSWORD = $DB_PASSWORD[3];
                }

                if (strpos($configline,"'DB_HOST'") > 0 ) {
                    $DB_HOST = (explode( "'", $configline));
                    $DB_HOST = $DB_HOST[3];
                }

                if (strpos($configline,"'DB_NAME'") > 0 ) {
                    $DB_NAME = (explode( "'", $configline));
                    $DB_NAME = $DB_NAME[3];
                }

                if (strpos($configline,"table_prefix") > 0 ) {
                    $tbl_prefix = (explode( "'", $configline));
                    $tbl_prefix = $tbl_prefix[1];
                }
            }
            // Connect to the wordpress database
            $con=mysqli_connect($DB_HOST,$DB_USER,$DB_PASSWORD,$DB_NAME) or die;

            // Check connection
            if (mysqli_connect_errno($con)) {
                echo "Failed to connect to MySQL: " . mysqli_connect_error();
            }

            // Retreve Site URL
            $sqlquery = "select option_value from " . $tbl_prefix . "options where option_name like 'siteurl'";
            $result = mysqli_query($con,$sqlquery);
            if (!$result) {
                echo "MySQL ERROR DIED! Retreve Site URL" . PHP_EOL;
                die('Invalid query: ' . mysql_error());
            }
            
            while($row = mysqli_fetch_array($result)) {
                $siteurl = $row['option_value'];
                $siteurl = (explode( "//", $siteurl));
                $siteurl = $siteurl[1];
            }
            // Write version of wordpress installation
            //echo "WP-Version is: " . $wpversion . PHP_EOL;

            // Retreve all Admins email address
            $sqlquery = "SELECT * FROM " . $tbl_prefix . "users JOIN " . $tbl_prefix . "usermeta ON ( " . $tbl_prefix . "users.id = " . $tbl_prefix . "usermeta.user_id ) WHERE " . $tbl_prefix . "usermeta.meta_key LIKE    'wp_user_level' AND " . $tbl_prefix . "usermeta.meta_value =    '10'";
            $result = mysqli_query($con,$sqlquery);
            if (!$result) {
                echo "MySQL ERROR DIED! Retreve all Admins email" . PHP_EOL;
                die('Invalid query: ' . mysql_error());
            }

            while($row = mysqli_fetch_array($result)) {
// Uncomment to send e-mail to all Admins.
//                send_email( $row['option_value'], $siteurl, $wpversion, $current_version);
                $tmp = $row['user_email'];
                array_push($adminEmail, $tmp);
            }

            // Retrive the Site Admin email address and spam them until they upgrade wordpress.
            $sqlquery = "select option_value from " . $tbl_prefix . "options where option_name like 'admin_email'";
            $result = mysqli_query($con,$sqlquery);
            
            if (!$result) {
                die('Invalid query: ' . mysql_error());
            }

            while($row = mysqli_fetch_array($result)) {
// Uncomment to send e-mail to all Site-Admins.        
//                send_email( $row['option_value'], $siteurl, $wpversion, $current_version);
                $tmp =  $row['option_value'];
                array_push($siteAdminEmail, $tmp);
            }
    
            mysqli_close($con);
        } else {
            echo "NO file found" . PHP_EOL;
        }
        $siteurlUTF8 = idn_to_utf8($siteurl);
        $adminEmailComma = join(", ", $adminEmail);
        $siteAdminEmailComma = join(", ", $siteAdminEmail);

        $summary .= $siteurlUTF8 . "
 ";
        $summary .= "version: " . $wpversion . "
 ";
        $summary .= "Admin Emails: " . $adminEmailComma . "
 ";
        $summary .= "SiteAdmin Emails: " . $siteAdminEmailComma . "

 " . "\r\n";
    }
}

// Comment next line to not send e-mail to server admin.sendAdminSummary($AdminAdress, $summary);


function send_email($address, $siteurl, $wpversion, $current_version){
    global $Sender;
    
    $to    = $address;
    $subject = "Detfinns en ny version av wordpress forsajten: " . idn_to_utf8($siteurl) ;
    $message = '' . $subject . '


Hej

Du får detta meddelande gäller sajten: ' . idn_to_utf8($siteurl) . '. 
Det har kommit en ny version ' . $current_version . ' av wordpress och eftersom du fortfarande använder version ' . $wpversion . ' så bör den upgraderas. 

Scandinavian Hosting


';

    $headers = 'MIME-Version: 1.0' . "\n";
    $headers .= 'Content-type: text/html; charset=utf-8' . "\n";
    $headers .= 'From: ' . $Sender . "\n";
    $headers .= 'Reply-To: ' . $Sender . "\n";

    mail($to, $subject, $message, $headers);
}


functionsendAdminSummary($address, $summary){
    global $current_version;
    global $ServerName;
    global $Sender;
    
    $to    = $address;
    $subject = "Sammanställning avWordpresssajter sombehöveruppdateras";
    $message = '' . $subject . '


Hej

Här kommer en sammanställning av sajter som behöver uppdateras på ' . $ServerName  . ' 
Senaste versionen av WordPress är ' . $current_version . '

 ' . $summary . '

Med Vänlig Hälsning
Scandinavian Hosting


';

    $headers = 'MIME-Version: 1.0' . "\n";
    $headers .= 'Content-type: text/html; charset=utf-8' . "\n";
    $headers .= 'From: ' . $Sender . "\n";
    $headers .= 'Reply-To: ' . $Sender . "\n";

    mail($to, $subject, $message, $headers);
}

// http://yalamber.com/2012/12/get-the-latest-version-number-of-wordpress-using-api/
function getData($url) {
    if(is_callable('curl_init')){
        $ch = curl_init();
        $timeout = 5;
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $timeout);
        $data = curl_exec($ch);
        curl_close($ch);
        return $data;
    }else{
        return file_get_contents($url);
    }
}

?>

 

The get it all to work I run the main script once a month, first monday at 8:00

cronetab-e

Add a line that looks like this:

0 8 * * 1 /root/scripts/wp-version/run-wp-version.sh

That is all
As always, post a comment if you find it useful.

Change all bindings in IIS to new IP

So I was migrating a web server from IIS 6 to IIS 8.5.
After the migration i needed to change IP on the new server. That’s not fun when all bindings are with IP.

So I decided to just Google a script that could change everything for me. I only found scripts that could change for a specific website and not all of them. So after some copy past and some trial and error I got this is result:

Import-Module Webadministration

$OldIP = "192.168.2.68:80"
$NewIP = "*:80"

$SiteNames = Get-ChildItem -Path IIS:\Sites | Select-Object name #-First 1

foreach ($name in $SiteNames){
    $txtName = $name.name
    #$name.name.gettype()
    
    $wsbindings = (Get-ItemProperty -Path "IIS:\Sites\$txtName" -Name Bindings)
    for($i=0;$i -lt ($wsbindings.Collection).length;$i++){
        $tmp = $wsbindings.Collection[$i].bindingInformation
        if ($tmp -match $OldIP){
            $tmp = $tmp -replace $OldIP, $NewIP 
            ($wsbindings.Collection[$i]).bindingInformation = $tmp;
            Set-ItemProperty -Path "IIS:\Sites\$txtName" -Name Bindings -Value $wsbindings
        }
    }
}

 

If you find it useful please leave a comment.

/Fredrik

Crashplan backup to Raspberry Pi

Raspberry Pi - Crashplan Server
My former employer decided to pull the plug on my old backup server. It was nothing special, just a Windows share, VSS and a PPTP tunnel. But it work for me, every night my homeserver connected to the server and by Robocopy /mir sync my folders so that any changes was reflected on the backup server.

When I got the notice that they wher going to pull the plug I started to look for a new solution that I could have up soon and had to be cheap.
I got a tips that Crashplan was something that I should have a look on. After some googling I found this link: http://www.bionoren.com/blog/2013/02/raspberry-pi-crashplan/

I had a Raspberry Pi lying around, I also had a 1TB SATA hard drive from my old homeserver, a USB/SATA Docking Stations and some other stuff.

After three week I managed to destroy the SD card, I had a backup but I decided to rebuild most of it and put / on the USB hard drive as well.

This is how I did it.
Installed the latest 2013-09-25-wheezy-raspbian.zip, NOOBS made more partitions on the SD card that I didn’t need.
Configure everything in raspi-config. Disabled Desktop, enabled SSH and set Graphics memory to 16MB. I’m using the old 256MB Raspberry PI model B.

I partitioned my USB hard drive in two partitions 16GB for rootfs and 850GB for /data
Used this guide to partition my USB hard drive and move root
http://www.raspberrypi.org/phpBB3/viewtopic.php?f=29&t=44177

After this I used the http://www.bionoren.com/blog/2013/02/raspberry-pi-crashplan/ to install java and Crashplan

To configure Crashplan headless:
http://support.crashplan.com/doku.php/how_to/configure_a_headless_client

I used putty.exe to set up the SSH tunnel, start it from command prompt:

putty -L 4200:localhost:4243 pi@<IPtoPI> -pw ********

I bought a new USB – SATA hard drive cabinet for the old 1TB hard drive.
New USB SATA Hard Drive Cabinet
It has a 2A power supply that I thought could power my Raspberry Pi as well, there aren’t a lot of normal power outlets in the computer center.
OLYMPUS DIGITAL CAMERA
The hard drive does not take that much power.OLYMPUS DIGITAL CAMERA

So I solder a micro USB cable to the 5volt on the SATA port. The circuit board locked the cable in place.
OLYMPUS DIGITAL CAMERAOLYMPUS DIGITAL CAMERA
Found the Kensington lock hole useful OLYMPUS DIGITAL CAMERA

Finished result:
OLYMPUS DIGITAL CAMERAOLYMPUS DIGITAL CAMERA

Since I put the Raspberry on the Internet and no other firewall in front of it I’m using Iptables. I’m not a hardcore user of Iptables so I found a nice GUI I could use on my PC: http://www.fwbuilder.org/
Real simple to use, didn’t lock me out once.

Update:
Since i only use the boot partition on the SD card i decided to replace my 8GB with an old 1GB that i haven’t used in a long time. If I only could find the SD card that I got when I bought my first digital camera. I think it was 32MB and that would have been enough.