PDA

Bekijk Volledige Versie : Yami Codes Applicleaner



Yami King
10/08/06, 02:16
Hey,

Ik ben sinds maandag (nadat een vriend van me, een hostingprovider een backdoor/trojan geschreven in PERL tegenkwam op zijn server) bezig met een script dat bestanden moet scannen op dit soort beveiligingsinfecties.

Het script verkeerd momenteel in versie 0.2, en ik zou graag willen weten of jullie er wat mee kunnen, ook zou ik graag feedback willen op dit script.

Uiteraard is dit script niet zomaar uitdeelbaar en mag het niet verkocht worden.

Het script bestaat uit 2 pagina's:
-- index.php

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<title>Yami Codes Applicleaner 0.1</title>
<style type='text/css'>@import "App_Data/stylesheets/default.css";</style>
</head>

<body>
<div class='title'>Scan options</div>
<form action='<?php $_SERVER['PHP_SELF']; ?>' method='post' id='form'>
<h2>Automaticly copy (possible) infected files to Quarantaine?</h2>
<label><input type='radio' name='pushq' value='1' checked="checked" /> Yes (recommended)</label>
<br />
<label><input type='radio' name='pushq' value='0' /> No</label>
<br />
<br />
<input type='submit' name='submit' value='Scan' />
<br />
<br />
*) Enabling this option will result in a longer results-loading time!
</form>
<?php
$submit = addslashes($_POST['submit']);

if ($submit <> 'Scan') {
exit;
}

$pushq = addslashes($_POST['pushq']);

if (!isset($pushq)) {
exit;
}
if ($pushq <> 1 && $pushq <> 0) {
$pushq = 1;
}
?>
<div class='title'>Results</div>
<div id='results'>
<?php

require_once 'App_Code/applicleaner.class.php';

Applicleaner::$pushToQuarantaine = $pushq;

Applicleaner::doDirScan('../virdir');
Applicleaner::displayThreats();
?>
</div>
</body>
</html>

-- applicleaner.class.php

<?php
/**
@author Yami King
@version 0.2

@deprecated
@action
Mailbomber zoeker
@todo
1) .htaccess-bestanden lezen for FilesMatch (file extension & mime herschrijving
onderscheppen = `rootkit` onderscheppen);
@changed
Deze nieuwe methode is geïmplementeerd door gewoon elk bestand te scannen
doordat veel servers hun eigen manier van het veranderen van mime-types hebben.
2) ftp_login's in doSendToLabs veranderen in sockets (CAPTCHA idee volgen).
@changed
Deze nieuwe methode is geïmplementeerd door gewoon elk bestand te mailen
naar de Labs i.p.v het huidige FTP en het idee voor sockets.
*/
final class Applicleaner {
private static $threats = array();
private static $illegal = array(
'apache_note',
'apache_setenv',
'closelog',
'connect',
'curl_exec',
'debugger_off',
'debugger_on',
'define_syslog_variables',
'escapeshellarg',
'escapeshellcmd',
'exec' => array(
'pattern' => '/(\*\/|\s{1}?)exec(\s{0}?)(\{|\(|)(\"|\'|)(.+)(\"|\'|)(\}|\)|)(.*)/ismU',
'name' => 'exec'
),
'openlog',
'parse_ini_file',
'passthru',
'pcntl_exec',
'proc_close',
'proc_get_status',
'proc_nice',
'proc_open',
'proc_terminate',
'shell_exec',
/* Shell execution using `` */
'shell_exec' => array(
'pattern' => '/(echo|print|\$(.*)|)(.*)(=|)(.*)`(.+)`/ismU',
'name' => 'quoted version of shell_exec'
),
'show_source',
'socket',
'socket_create',
'stream_socket_client',
'stream_socket_server',
'syscall',
'syslog',
'sysrun',
'system',
);
public static $threatCount = 0;
public static $pthreatCount = 0;
public static $report = NULL;
private static $called = array('dirscan' => 0, 'filescan' => 0);
public static $pushToQuarantaine = 1;

public static function doDirScan($dir) {
self::$called['dirscan'] = 1;

$dir = str_replace('\\', '/', $dir);

if (substr($dir, -1) <> '/') {
$dir .= '/';
}
if (!is_dir($dir) || is_file($dir)) {
self::$report .= "<br><u>/!\</u> Unable to scan the directory (".$dir.") while it doesn't exist or is a file!";
}

$dh = scandir($dir);

if ($dh) {
for ($i = 2; $i < count($dh); $i++) {
if (is_dir($dir.$dh[$i]) && !is_file($dir.$dh[$i])) {
self::doDirScan($dir.$dh[$i].'/');
}
else {
if (sha1_file($dir.$dh[$i]) <> sha1_file('App_Code/applicleaner.class.php')) {
self::doFileScan($dir.$dh[$i]);
}
}
}
}
else {
self::$report .= '<br>Unable to scan the directory ('.$dir.')!';
}
}
public static function doFileScan($file) {
if (self::$called['dirscan'] <> 1) {
self::$report = "<br><u>/!\</u> Unable to scan a file without scanning a directory!";
self::displaythreats();
exit(1);
}

$fh = htmlspecialchars(@file_get_contents($file));
self::$threats[$file] = array();

foreach (self::$illegal as $i) {
if (is_array($i)) {
if (preg_match($i['pattern'], $fh)) {
array_push(self::$threats[$file], $i['name']);
}
}

$patterns = array(
"/(.*)".$i."\(.*\)(.*)(;|)(.*)/ismU",
"/(.*)".$i."\{.*\}(.*)(;|)(.*)/ismU",
"/(.*)".$i."\s{1}\(.*\)(.*)(;|)(.*)/ismU",
"/(.*)".$i."\s{1}\{.*\}(.*)(;|)(.*)/ismU"
);

foreach ($patterns as $pattern) {
if (preg_match($pattern, $fh)) {
array_push(self::$threats[$file], $i);
}
}
}

if (!empty(self::$threats[$file]) && self::$pushToQuarantaine == 1) {
Applicleaner::doPushToQuarantaine($file);
}
}
public static function doPushToQuarantaine($file) {
$file = str_replace('\\', '/', $file);
$dest = substr($file, strrpos($file, '/') + 1);
$dest = 'Quarantaine/NotHealed/'.$dest;

while (@file_exists($dest.'.txt')) {
$dest .= abs(crc32(rand(0, 999999)));
}

if (@copy($file, $dest.'.txt')) {
self::$report .= "<br>Successfully pushed file (".$file.") to the Quarantaine!";
}
else {
self::$report .= "<br><u>/!\</u> Unable to push file (".$file.") to the Quarantaine!";
}
}
public static function displayThreats() {
foreach (array_keys(self::$threats) as $t) {
echo $t.'<br>';

if (count(self::$threats[$t]) == 0) {
echo "&nbsp;&nbsp;&nbsp;&nbsp;<img src='App_Data/images/secure.gif' style='width: 16px;'> <span style='color: #0C0; font-weight: bold;'>No instability found!</span><br />";
}
else {
foreach (self::$threats[$t] as $tt) {
if ($tt == 'socket' || $tt == 'socket_create' || $tt == 'connect' || $tt == 'stream_socket_server' || $tt == 'stream_socket_client') {
echo "&nbsp;&nbsp;&nbsp;&nbsp;<img src='App_Data/images/harmful.gif' style='width: 16px;'> <span style='color: #DD0; font-weight: bold;'><u>/!\</u> Possible instability found: ".$tt."()!</span><br />";

self::$pthreatCount++;
}
else {
echo "&nbsp;&nbsp;&nbsp;&nbsp;<img src='App_Data/images/insecure.gif' style='width: 16px;'> <span style='color: #F00; font-weight: bold;'><u>/!\</u> Instability found: ".$tt."()!</span><br />";

self::$threatCount++;
}
}
}
}

if (empty(self::$report)) {
$report = '<br>-';
}
else {
$report = self::$report;
}

echo "<hr style='border: 1px solid #BBB;'><b>Report:</b>".$report;
}
}
?>

Om de applicatie te gebruiken dien je de zip file te downloaden (er zitten namelijk ook nog plaatjes en een aantal benodigde mappen bij).

Graag serieuze replies XD.


BTW: Het is niet verstandig de scripts die in de test-vir-dir zitten uit te voeren!

Download:
4458

Wido
10/08/06, 10:07
Ik denk dat je er even bij moet melden dat het PHP5 is ;)

gjtje
10/08/06, 10:16
Yes/no is meestal een checkbox. Waarom is alles static?

Je zou een dergelijk script eigenlijk vanaf de commandline moetenrunnen, een goed geconfigureerde webserver zal nooit toe staan dat je alle mogelijke folders kunt scannen (nou zou je daar misschien het script ook niet nodig hebben maar toch ;)).

Yami King
10/08/06, 10:51
Ik denk dat je er even bij moet melden dat het PHP5 is ;)
Ja idd, dat had ik er eigenlijk even bij moeten zetten.


Yes/no is meestal een checkbox. Waarom is alles static?

Je zou een dergelijk script eigenlijk vanaf de commandline moetenrunnen, een goed geconfigureerde webserver zal nooit toe staan dat je alle mogelijke folders kunt scannen (nou zou je daar misschien het script ook niet nodig hebben maar toch ;) ).
Yes/no is uiteraard een radio button, je mag mar 1 van de 2 kunnen kiezen.
Alles is static omdat dat een persoonlijke voorkeur had bij dit script.

Idd ik zou er nog een `cli` versie bij kunnen doen ja (deze hou ik zoiezo nog wel zo even bij ook XD).


Bedankt iig voor de antwoorden XD