发布于2025年12月5日12月5日 ## 前言 我第一次萌生写一个免杀WebShell的想法是本月初上网的时候。无意间看到阿里安全应急平台线上活动“第三届镇妖恶意代码挑战赛”报名公告。简单看了一下,我发现比赛的内容是用PHP、JSP、Python或者Bash语言编写后门代码。如果编写的代码通过阿里巴巴最新一代检测引擎(即Challenge Range)的检测,且不与其他高手重复,则比赛通过。 由于我对PHP语言和网络安全了解很多,所以我报名了PHP Track,打算尝试一下。经过4天的努力,编写了一个215行的PHP命令执行后门,并成功通过了现有数十个云反病毒引擎的检测。但还是很遗憾。当比赛射击场开放时,我上传了后门进行测试。最终我没能通过比赛,心里有些失望(毕竟这是我第一次接触QwQ)。 ┐=͟͟͞͞( ̄ー ̄)┌ 于是询问了钉钉群负责人后,我们决定在比赛结束后发布WebShell。算是一次学习经历: 项目地址:1.PerlinPuzzle-Webshell-PHP - Gitee PerlinPuzzle-Webshell-PHP - GitHub ## 声明 在我于2024 年1 月19 日披露这个WebShell 之前,我从未向任何安全平台提交过绕过漏洞报告,也没有从任何安全平台收到过任何bug 赏金或安全币。 ## 绕过情况 文件MD5值:7c0aeaec06454e588120877fd18cd0c8 文件SHA256 值:f53d5dd4de1b39ba5e5751f42f5e97b1a28383cf81c276151ef6066661f4f2b6 最后一次绕过测试于2024年1月18日进行,共使用35个云反病毒引擎进行检测,其中34个成功通过,病毒报告率为2.9%。 成功通过: - 阿里复魔引擎 - 安恒云沙盒 - 大圣云沙盒(风险评分0.19) - Hippo WebShell 查杀 - 魔盾云沙盒 - 总共26个微步集成引擎(Microsoft、Kaspersky、IKARUS、Avast、GDATA、Antiy、360、NANO、Rising、Sophos、WebShell、MicroAPT、OneStatic、ESET、小红三、Big Spider、AVG、K7、江民、百度、TrustBook、Panda、ClamAV、百度中国、OneAV、MicroNonPE) -D盾 - Windows 防御者 - Tinder 安全软件 失败: - 长汀百川WebShell检测平台 (VirusTotal 的另一张临时截图) ## 如何使用 要使用此WebShell,您需要向POST方法添加3个参数: - wpstring = ABBCCD - b ˆ ˆ ˆ ˆ=ˆ ˆ ˆ s - pcs = 要执行的命令 例如: ```` POST /perlin.php HTTP/1.1 主机: 127.0.0.1:7000 用户代理: Mozilla/5.0(X11;Linux x86_64;rv:109.0)Gecko/20100101 Firefox/116.0 Accept: 文本/html,应用程序/xhtml+xml,应用程序/xml;q=0.9,图像/avif,图像/webp,*/*;q=0.8 Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2 Accept-Encoding: gzip、deflate、br Content-Type: 应用程序/x-www-form-urlencoded 连接:关闭 升级不安全请求: 1 Sec-Fetch-Dest: 文档 Sec-Fetch-Mode: 导航 Sec-Fetch-Site: 无 Sec-Fetch-User:1 内容长度: 35 wpstring=ABBCCDb=spcs=hostnamectl `` ## 运行环境 1. 操作系统:Windows、Linux、macOS 2. PHP版本:PHP 5完整版、PHP 7完整版、PHP 8完整版 ## 绕过点介绍 - 使用故意编写的变量来覆盖传递参数的漏洞; - 利用线性代数循环群运算原理制作程序锁; - 将关键危险字符添加到“Perlin Noise”随机数生成算法生成的数组中; - 严重危险字符的生成内容由程序锁的运行结果决定。如果操作错误,则无法生成正确的字符; - 在程序执行期间使用拦截器。如果没有解锁,则阻塞函数返回值传输。 - 用很长的行注释干扰词汇引擎。 ## 技术原理说明 该WebShell 由4 个模块组成: - InazumaPuzzle 程序储物柜类 - PerlinNoise危险函数生成和执行类 - 变量值转移覆盖模块 - 代码执行阻塞模块 下面将对这四个模块进行一一说明。 ### 变量值传递覆盖模块 在介绍这个模块之前,我们首先需要了解一下变量覆盖漏洞。 变量覆盖漏洞:可以用自定义参数值替换原始变量值的漏洞。 在PHP实际开发中,我们经常使用以下语句: 相信很多熟悉PHP的读者都知道,这是从HTTP请求注册变量的代码。此代码使用foreach 语句遍历请求数组,然后根据HTTP 参数名称依次创建变量。使用这种方法可以大大简化我们的开发过程,但是如果某些关键变量可以被攻击者控制会发生什么? 此时攻击者可以通过GET或POST控制$security_check变量。如果传入一个假值,程序的SQL注入检查就会被关闭,从而导致SQL注入。 (前提是关键变量的赋值定义没有出现在变量注册语句之后) 这个WebShell特意引入了一个变量覆盖语句,并使用该语句传递关键参数: 上面的代码中,使用foreach语句遍历请求数组来注册变量,然后验证程序解锁的答案的长度,然后将解锁的答案复制到数组中。这样程序锁就可以使用解锁答案。 ### 代码执行阻塞模块 该模块由pause()函数组成。该函数接收程序流程的返回值,并检查程序的解锁状态。如果程序解锁,则返回值传递给下面的程序流程。如果没有解锁,则使用die()函数退出程序: 该模块主要用于针对云扫查引擎进行动态污点分析。 ### InazumaPuzzle 程序储物柜 为了对抗云反病毒引擎的动态污点分析,本程序实现了一个线性代数循环群运算模拟器。该模块接收一个PHP数组形式的传入值,然后根据传入值对对象中的四个成员变量进行循环分组操作。当操作完成后,如果四个成员变量的值相等,则认为程序已解锁。 该模块的设计灵感来自于开放世界游戏《原神》中广泛存在于闪电地区的大世界解谜机制阵列“机关方块”。机构阵列由多个小立方体机构组成。当其中一个机构被击中时,它将链接阵列中的其他组件一起旋转。其本质是实现一个线性代数中“循环群”的计算模拟系统。原理图如下: 将其转换为线性代数方程如下: 作者根据上述内容编写了程序解锁模块类InazumaPuzzle。该类中有4个关键的类成员变量,blockA、blockB、blockC、blockD,用于存储上图中四个机制块的状态;该类还具有以下关键成员函数: - setBackBlock() - 命中() - __AFG50CE4_RG1() -getLockerStatus() 其中,setBackBlock()函数的作用是当要操作的成员变量的值即将超过循环组$maxType的最大值时,将其重置为循环组$setType的最小值。代码如下:(最大值为2,最小值为0) 可见,如果成员变量的整数值没有达到临界值,则返回false,不对成员变量进行操作;如果达到临界值,则重置并返回true。 根据原理图公式中的数量Aj编写hit()函数的功能,模拟“击中一个方块带动周围方块旋转”的功能: 可以看到这个函数的核心就是调用setBackBlock()函数或者给成员函数值加1。如果setBackBlock()函数返回true,则说明该成员函数值已经使用循环组操作方法加1了,不需要再次加1;否则手动加1。 (例如,如果接收到的传入值为A,则命中A、B;如果传入值为B,则命中A、B、C;以此类推) __AFG50CE4_RG1()函数的作用是接收答案数组,并根据数组的每个值调用hit()函数。它根据答案值模拟击中盒子。代码如下: 可以看到,该函数首先加载由变量覆盖传值模块初始化的答案数组变量$puzz_writeup;然后检查数组的长度以及数组中每个答案字符串,如果不符合格式要求则退出程序;然后遍历数组,取出数组中的每个字符串,并作为参数调用hit()函数,实现“hit”功能;最后初始化全局变量$userans,并将其值设置为对象中四个成员变量的总和。 附:根据类构造函数的设计,四个成员变量的初始值分别为2、0、0、2。如果命中正确,四个数字的总和应该是8。 getLockerStatus()函数的功能非常简单。它只是判断对象中的四个成员变量的值是否相等。如果相等,则判定该程序已解锁。代码如下: 在程序的主干中,程序首先使用变量覆盖值传递模块来传递关键变量,然后初始化InazumaPuzzle类并调用__AFG50CE4_RG1()解锁函数来尝试解锁程序。如果解锁失败,则以下PerlinNoise类无法初始化,程序退出,如图: ### PerlinNoise 危险函数生成和执行类 柏林噪声:一种随机数生成算法。柏林噪声以随机性为基础,在此基础上利用缓动曲线进行平滑插值,使得最终的噪声效果更加自然。根据采样空间的不同,Perlin噪声可分为一维、二维和三维。这种随机数生成算法常用于计算机图形学中。 通常,一维柏林函数生成器代码如下所示: ```` int[] perm={.}; 浮点数[] grad={.}; void Hash(ref int[] 梯度, int x, int y) { int permIdx[]=new int[2]; permIdx[0]=FindIndex(x); permIdx[1]=FindIndex(y); int gradIdx[]=新int[2]; gradIdx[0]=perm[permIdx[0]]; gradIdx[1]=perm[permIdx[1]]; 梯度[0]=grad[gradIdx[0]]; 梯度[1]=grad[gradIdx[1]]; } 浮动柏林(浮动x){ int x1=地板(x); int x2=x1 + 1; 浮动grad1=perm[x1 % 255] * 2.0 - 255.0; 浮动grad2=perm[x2 % 255] * 2.0 - 255.0; 浮点数vec1=x - x1; 浮点数vec3=x - x2; 浮点数t=3 * pow(vec1, 2) - 2 * pow(vec1, 3); 浮动产品1=grad1 * vec1; 浮动产品2=grad2 * vec2; 返回产品1 + t * (产品2 - 产品1); } ```` 但作者修改了一维柏林函数生成算法,在生成数组的第400~405位埋入了后门,实现了命令执行函数system()的隐藏调用。 该类中有以下几个关键函数: -构造函数 - randomFloat() 基于时间的随机值生成器 - __PLvB4CR0_Z() 排列表生成器 - __PLAB4CR0_o() 梯度表生成器 - __CPRBB0R0_l() 带有埋藏后门的柏林噪声发生器 - __HNBB70CA_5()柏林噪声监视器,带有埋藏后门 接下来依次介绍上述功能。 #### 构造函数 构造函数接收4 个参数: - arrlength Perlin噪声数组长度; - MAX_INPUT 最大渐变数; - MIN_INPUT 最小梯度数; - source 梯度值数据源(如果DIFF_PERLIN开启后门模式) 构造函数首先加载全局程序锁对象,然后调用InazumaPuzzle:getLockerStatus()方法来判断程序锁状态。如果未解锁,则退出程序;然后确定要生成的柏林噪声数的数量;如果不符合要求,就会报错;然后根据source参数判断是否开启后门模式。最后将4个参数配置保存在类成员变量中。 #### 基于时间的随机值生成器 randomFloat()函数的原理比较简单,就是根据时间种子和梯度数的极值配置生成每个梯度数。生成的梯度数是小数: #### 排列表生成器 __PLvB4CR0_Z() 函数是一个排列表生成器。该函数实际上是一个基于时间的随机整数生成器。生成的数字是指定的柏林噪声数组长度,保存在类中的数组成员变量$seeds_array中: #### 梯度表生成器 __PLAB4CR0_o()函数是梯度表生成器,其实际功能比较简单。该函数读取类成员变量$source的值,根据这个值确定梯度数的数据源(实际上只能生成随机值),然后调用randomFloat()函数生成2个随机小数。生成的数字是指定的柏林噪声数组长度。生成的数组存放在类数组成员变量$inputNumArray中: #### 带埋后门的Perlin 噪声发生器 __CPRBB0R0_l()函数是柏林噪声发生器,该函数中嵌入了后门。该函数首先加载全局变量$userans,它的值是lock的四个成员变量的和(一般为8);然后它根据变量$userans的值进行数学运算,指定生成危险功能字母的ASCII值,并将其写入特定位置。 (位400 到405)其他位是正常的Perlin 噪声数。生成的Perlin噪声数组保存在类数组成员变量$perlin_noise中。 #### 柏林噪声监测仪 __HNBB70CA_5() 函数是柏林噪声显示。该函数使用动态函数调用来执行system()命令来执行该函数。该函数首先使用EL表达式和数字到字符串转换加载三个变量$userans、$b和$pcs(其中$b是危险函数的首字母,$pcs是要执行的命令),然后读取Perlin噪声数组$perlin_noise中危险函数名称区域的值并将其保存到数组$cache_noise中,然后将其值复制到数组$temp_noise中(复制时故意少读一位),然后将其转换为字符串并多次反转、拼接和阻塞。 system()函数在整个程序的第123行执行。 ### 项目骨干 可以看到,InazumaPuzzle程序锁首先在程序的主干部分创建,然后调用InazumaPuzzle:__AFG50CE4_RG1()函数尝试解锁程序。然后程序创建了一个带有后门的Perlin噪声生成器并开启后门模式,然后生成梯度表和排名表,最后调用内置后门的Perlin噪声打印函数来执行命令。 ## 参考文献 - [[数学原理]闪电魔方解密数学原理-原神影响社区-米有社](https://link.juejin.cn/?target=https%3A%2F%2Fwww.miyoushe.com%2Fys%2Farticle%2F17414097) - [[代码本质]柏林噪音-知乎](https://link.juejin.cn/?target=https%3A%2F%2Fzhuanlan.zhihu.com%2Fp%2F206271895%3Fivk_sa%3D1024320u%26utm_id%3D0) - [可变覆盖漏洞汇总-CSDN博客](https://link.juejin.cn/?target=https%3A%2F%2Fblog.csdn.net%2Fqq_45521281%2Farticle%2Fdetails%2F105849770) 转载自稀土掘金:https://juejin.cn/post/7325495635457130506 作者:御坂No.19008
创建帐户或登录后发表意见