SingleAdminGuard 防护插件的心路历程

值得一看2026年10月1日更新 E导航
89 0 0

很多人以为网站入侵一定会留下明显痕迹,实际踩坑后才发现未必。我先后遭遇两次完全不同的攻击,一次无文件提权新增管理员,一次植入 WebShell,后者能被发现甚至带有运气成分。下面记录这两段真实经历,也是我开发防护插件的缘由。

凌晨一点的那封邮件

7月2日凌晨一点,我还没睡。正在改插件——邮件提示音响了一下,是注册通知。

我随手点开,扫了一眼用户名:c3test@pwn.local。手停住了。pwn,搞渗透打攻防的人挂在嘴边的一个词,意思是”拿下”。.local 是本地测试域名的后缀,正经人注册网站不会填这个。

这两个东西凑一起,就不是”用户注册”,是有人在拿我的站练手。

我立刻切到用户列表——管理员。一个刚注册进来的账号,权限直接就是管理员。

那天晚上我后台什么防护都没装。也就是说,从它注册成功的那一刻起,这个站已经不完全是我的了。

SingleAdminGuard 的第一行代码,是那封凌晨一点的邮件逼出来的。

群里隔三差五就有人说这个

后来我在 OneNav 的交流群里,总能看到同一类消息。

说法都差不多:主题的 REST API batch/v1 端点有提权漏洞——能绕过权限校验,在一个请求里把一批操作全执行了。中招的表现也高度一致:后台莫名多出管理员,或者站点被挂马。

群里一堆人喊中招。我基本没说话。我的站早就已经被打过了,他们说的那个洞,我大概知道长什么样。

8 月 18 号,测试站服务器变得很慢

我服务器上只挂了一个测试站。就一个站,访问却慢得不正常。

我去翻错误日志——本来没抱什么希望,就是习惯性看一眼。

然后我看到了一行很短的东西:

PHP Fa tal error: Uncaught Error: Call to undefined function ... in /tmp/.cache:xx

报错的位置是 /tmp/.cache。我盯着这行看了很久,越看越不对。

我的站点代码全在网站根目录底下。谁会在 /tmp 里跑 PHP? 而且文件名是 .cache——一个没有扩展名的隐藏文件。这东西要不是报错把路径吐出来,我平时翻一百遍目录都不会看它一眼。

顺着这行报错往下挖,在网站根目录找到了一个文件:stack.php。拉出来一看。是马。

说句实话:不是 PHP版本高真不知道

这个马写文件的手法挺老派——它不直接写 file_put_contents 这种敏感词,而是先取出”所有已定义的内部函数”那个数组,再靠下标去调:

$funcs = get_defined_functions();
$funcs['internal'][151]($$output_file);

用意很直白:源码里搜不到任何敏感函数名,静态扫描扫不出来。

但从 PHP 8.0 开始,这招废了。get_defined_functions()[‘internal’][151] 返回的数组顺序不再是固定的——不同版本、不同编译参数、不同扩展加载顺序,下标 151 指的根本不是同一个函数。

我的站跑的是 PHP 8.3。这行当场抛 Fatal Error。

关键点:报错里的 @ 抑制符压不住 Fatal Error。 马里到处是 @fopen、@tempnam,但 @ 只能压住 Warning 和 Notice,压不住致命错误。

所以这行报错老老实实写进了日志,连文件路径一起,把自己的藏身之处交了出来。

要是我的站跑的是 PHP 7,这一行会正常执行完。日志干干净净。我到现在都不会知道自己中过招。

两个站是两波攻击,不是一波

7 月 2 号那波:REST API batch/v1 提权,直接写库,后台莫名多出管理员。目录里搜不到,只能靠用户表去发现。
8 月 18 号那波:无管理员账号直接落文件:写 stack.php + include 执行,服务器变慢、日志里露出路径。只能靠不让它执行(noexec /open_basedir)。

结语

两次攻击是两种完全不同的入侵思路:一类无文件、直接篡改数据库新增管理员;另一类上传 WebShell,尝试落地恶意代码。
这次能发现后门纯属运气,PHP8.3 让黑客的隐藏写法失效,报错暴露痕迹。
网站安全不能只靠查杀木马,管理员账号监控、临时目录限制、权限加固,多维度防护缺一不可。

© 版权声明

相关文章

暂无评论

none
暂无评论...