1. 项目概述从一道蓝桥杯Web题切入CTF实战如果你对网络安全感兴趣或者听说过CTFCapture The Flag夺旗赛但觉得它高深莫测那么这篇文章就是为你准备的。我们不谈那些复杂的底层协议和汇编指令就从一道非常经典的、来自蓝桥杯的Web题目“黑客密室逃脱”开始。这道题完美地融合了两个在CTF Web方向中极为常见的考点Flask框架下的文件包含漏洞和自定义加密算法的逆向分析。对于新手来说它就像一座精心设计的“密室”既有明确的线索漏洞点又有需要动脑破解的“锁”加密逻辑。通过拆解这道题你不仅能亲手拿到Flag比赛中的目标字符串更能透彻理解这两个漏洞的原理、利用方法以及背后的安全思想。无论你是计算机专业的学生还是希望转行安全领域的开发者甚至是单纯对“黑客技术”感到好奇的爱好者这篇指南都将带你跨出从理论到实战的关键一步。2. 核心漏洞原理深度解析在动手解题之前我们必须先搞清楚要面对的是什么。题目基于Flask框架这决定了我们的攻击面漏洞点是文件包含这是我们突破的入口而自定义加密则是我们获取最终Flag前必须解开的谜题。2.1 Flask框架与潜在的风险点Flask是一个轻量级的Python Web框架以其灵活和简洁著称。开发者通过定义路由app.route和处理函数来构建应用。在本题中风险往往源于开发者对用户输入过于信任。例如一个常见的危险操作是使用render_template函数或send_from_directory函数时直接拼接了用户可控的变量。想象一下如果代码中有一行类似send_from_directory(‘./templates‘, filename)的语句而filename这个参数完全由用户通过URL参数如?filexxx控制那么危险就产生了。攻击者可以通过构造特殊的filename值如../../etc/passwd让服务器读取并返回本不应被访问的系统文件。这就是路径遍历攻击是文件包含漏洞的一种常见形式。Flask本身并不“脆弱”脆弱的是开发者不安全的使用方式。2.2 文件包含漏洞LFI的攻防本质文件包含漏洞尤其是本地文件包含Local File Inclusion, LFI允许攻击者通过Web应用动态包含服务器本地的文件。其危害极大因为攻击者可能读取到配置文件如/etc/passwdLinux用户信息、/proc/self/environ进程环境变量可能包含密钥。源代码通过包含.py文件或利用PHP等语言的特性本题是Flask但原理相通来获取应用逻辑。日志文件在特定条件下向日志中写入恶意代码再包含该日志文件以执行代码。在CTF中LFI的利用常常是为了获取源代码从而发现更多的漏洞线索比如本题中的加密逻辑。防御的关键在于对用户输入进行严格的过滤和校验比如限制包含的文件路径必须在某个安全目录内或使用白名单机制。2.3 自定义加密CTF中的“锁匠”挑战CTF题目很少使用标准的、强加密算法如AES因为那对于解题来说往往意味着暴力破解缺乏技巧性。出题人偏爱自定义加密或弱加密。这种加密可能只是简单的字符替换如凯撒密码、Base64变种、逻辑运算XOR或者是几种简单操作的组合。解题者的任务就是扮演“锁匠”通过分析有限的加密/解密样本通常是题目给出的输入输出对逆向推断出加密算法的逻辑。这需要一定的观察力、逻辑思维和编程能力。在本题中我们最终需要逆向的很可能就是一个用于验证身份或生成关键信息的自定义函数。3. 靶场环境搭建与题目复现“纸上得来终觉浅绝知此事要躬行。” 要真正学会最好的方法就是自己动手把题目跑起来。3.1 使用Docker快速构建漏洞环境对于CTF学习我强烈推荐使用Docker。它能让你的实验环境与主机隔离避免搞乱系统并且一键部署极其方便。准备Dockerfile如果题目方没有提供现成的镜像我们需要根据题目描述或逆向得到的源码编写Dockerfile。一个典型的用于Flask题目的Dockerfile如下FROM python:3.9-slim WORKDIR /app COPY requirements.txt . RUN pip install --no-cache-dir -r requirements.txt COPY . . CMD [“python”, “app.py”]这里基于Python 3.9精简镜像将工作目录设为/app复制依赖文件并安装最后复制所有应用代码并启动。编写requirements.txt这个文件列出了项目依赖。flask2.0.1构建与运行# 在包含Dockerfile和app.py的目录下执行 docker build -t ctf-flask-lfi . docker run -p 8080:8080 --name my-ctf-challenge ctf-flask-lfi现在访问http://localhost:8080就能看到题目界面了。注意在真实CTF或蓝桥杯比赛中题目是远程在线提供的。本地搭建是为了方便我们反复调试、深入分析尤其是查看服务端打印的调试信息这在远程环境中是不可能的。3.2 题目初步信息收集启动环境后第一步不是盲目测试而是进行“侦察”。前端观察打开网页查看所有可见的链接、表单、按钮和注释CtrlU查看网页源代码。寻找任何提示比如注释里可能写着!-- debug: source code in /source --。目录扫描使用工具如dirsearch或gobuster进行简单的目录爆破寻找常见的备份文件、源码文件或管理界面。dirsearch -u http://localhost:8080 -e php,py,txt,bak,zip,tar.gz可能会发现/app.py/www.zip/source等线索。参数探测观察URL。如果看到类似?pageabout.html这样的参数立即警觉这很可能就是文件包含的点。尝试修改为?page../../../../etc/passwd进行测试。4. 漏洞利用文件包含实战突破假设通过信息收集我们发现了URL中存在一个file参数用于加载模板http://localhost:8080/show?filewelcome.html。4.1 基础路径遍历测试我们的目标是读取应用的源代码app.py因为加密逻辑一定写在里面。尝试直接读取?fileapp.py。如果直接返回了代码那题目就太简单了。通常会有路径限制。使用路径遍历?file../../app.py。这里../表示上一级目录。我们需要猜测应用当前的相对路径。假设Flask应用从/app目录运行模板在/app/templates那么../../就能退回到根目录再进入/app。使用绝对路径在某些配置下可以直接使用绝对路径如?file/app/app.py。利用PHP包装器非本题但重要如果是PHP环境php://filter协议是神器可以读取文件源码并进行Base64编码输出避免代码被直接执行。例如?filephp://filter/convert.base64-encode/resourceindex.php。但在纯Flask/Python环境下这个技巧无效。4.2 进阶技巧利用Flask特性获取源码在无法直接穿越目录时我们需要更巧妙的思路。Flask在调试模式下如果触发服务器错误会返回一个包含错误信息和局部变量值的交互式调试页面。虽然生产环境会关闭它但CTF题有时会开启。我们可以尝试触发一个错误比如传入一个不存在的文件名或者利用参数类型错误让错误信息泄露部分代码栈信息。但这方法不稳定。更可靠的方法是如果文件包含点能读取到Python的临时文件或被导入的模块文件吗这通常很难。在本题“黑客密室逃脱”的典型设定中突破口往往是一个“源码泄露”。例如通过?file....//....//....//app.py这样的多重URL编码../编码为%2e%2e%2f绕过简单的过滤或者题目本身就预留了一个路由/source或/debug来直接显示源码。作为新手一定要养成检查常见源码泄露路径的习惯。假设我们通过?file....//....//app.py成功读取到了app.py的源代码。接下来就是代码审计时间。5. 代码审计与加密逻辑逆向拿到源代码后我们就像拿到了密室的建筑图纸。快速浏览代码寻找几个关键部分路由定义所有app.route的地方特别是处理我们刚才利用的file参数的路由。加密/解密函数寻找名为encryptdecryptcryptocheck_token等的函数或者涉及hashlib、异或^运算、字符循环移位等操作的自定义函数。Flag生成或输出逻辑寻找像flagFLAGsecret这样的变量或者最终输出Flag的条件语句。5.1 分析示例加密函数假设我们在app.py中找到了如下函数def weird_encrypt(text): key “SECRET_KEY_HERE“[:len(text)] result ““ for i, c in enumerate(text): result chr((ord(c) ord(key[i]) - 2*ord(‘A‘)) % 26 ord(‘A‘)) return result这是一个典型的流加密逐字符加密。我们来逆向分析key被截取成和明文一样长。对明文的每个字符c和密钥对应字符key[i]进行运算(ord(c) ord(key[i]) - 2*ord(‘A‘)) % 26 ord(‘A‘)。ord(‘A‘)是65。这个运算的本质是将字符c和key[i]都视为0-25的数字A0, B1, ... Z25然后相加后取模26再转换回字符。这实际上是**维吉尼亚密码Vigenère cipher**的一种变体解密过程就是逆运算chr((ord(c_encrypted) - ord(key[i]) 26) % 26 ord(‘A‘))。5.2 寻找密钥与构造解密器现在我们知道它是维吉尼亚密码但密钥key是什么继续审计代码。密钥可能硬编码在代码里也可能来自某个文件我们之前用LFI读到的/proc/self/environ或配置文件或者通过某个路由计算出来。假设我们在另一个路由/get_key中发现返回了密钥的Base64编码。或者密钥就是SECRET_KEY_HERE。那么我们就可以编写Python解密脚本了。def weird_decrypt(enc_text, key): key key[:len(enc_text)] result ““ for i, c in enumerate(enc_text): # 逆向运算加密是 (p k) % 26 解密就是 (c - k 26) % 26 p (ord(c) - ord(‘A‘) - (ord(key[i]) - ord(‘A‘)) 26) % 26 result chr(p ord(‘A‘)) return result # 假设我们从题目响应中获取了密文和密钥 ciphertext “LXFOPVEFRNHR“ # 示例密文 key “SECRET“ plaintext weird_decrypt(ciphertext, key) print(plaintext) # 输出解密结果6. 整合利用链获取最终Flag通常CTF题的Flag不会直接放在一个能被LFI读取的文本文件里。它需要我们将前几步串联起来形成一个完整的利用链。一个典型的流程可能是利用LFI读取/app/app.py 获得源代码。审计代码发现访问/flag路由需要提供一个有效的token。分析token的生成算法。代码显示token encrypt(username “|“ timestamp) 其中encrypt就是我们刚才分析的自定义函数。寻找密钥。代码中可能写死了密钥或者密钥来自环境变量。我们可以尝试用LFI读取/proc/self/environLinux下进程环境变量文件里面可能包含SECRET_KEYxxxxx。伪造token。知道了加密算法和密钥我们就可以为任意用户名和时间戳生成合法的token。通常题目要求管理员用户比如usernameadmin。构造请求。带着伪造的token访问/flag路由服务器验证通过返回Flag。import requests import time BASE_URL “http://localhost:8080“ # 1. 读取源码假设漏洞点 source_code requests.get(f“{BASE_URL}/show?file....//....//app.py“).text print(“[] Source code obtained.“) # 此处省略代码解析和密钥提取过程假设我们已得到密钥 MY_SECRET_KEY KEY “MY_SECRET_KEY“ # 2. 根据加密算法生成token def generate_token(username): timestamp int(time.time()) plain f“{username}|{timestamp}“ token weird_encrypt(plain, KEY) # 使用前面分析出的加密函数 return token # 3. 以admin身份请求flag admin_token generate_token(“admin“) flag_resp requests.get(f“{BASE_URL}/flag“, cookies{“token“: admin_token}) # 或者可能是POST请求token在参数里 # flag_resp requests.post(f“{BASE_URL}/flag“, data{“token“: admin_token}) print(“[] Flag response:“, flag_resp.text) # 在响应中寻找类似 flag{...} 格式的字符串7. 常见问题与调试技巧实录在实际操作中你一定会遇到各种问题。下面是我踩过的一些坑和总结的技巧。7.1 文件包含漏洞利用失败问题../被过滤或转义了。排查尝试URL编码..%2f(/的编码)%2e%2e%2f(../的编码)。尝试双重编码%252e%252e%252f对%2e的%再次编码。尝试绝对路径/etc/passwd。尝试空字节截断在较老版本PHP中有效Python/Flask中通常无效../../etc/passwd%00。查看服务器返回的错误信息可能提示了过滤规则。心得永远不要只试一种payload。准备一个payload字典用Burp Suite的Intruder模块进行模糊测试效率最高。7.2 加密算法逆向困难问题加密函数逻辑复杂一眼看不出是什么。排查黑盒测试如果题目提供加密接口输入有规律的数据如‘A‘*10‘ABCDEFG‘观察输出。这能帮你判断是分组加密还是流加密是否有移位、替换等。静态分析在代码中给加密函数插入print语句在本地复现的环境里打印中间变量值。这是最有效的方法。搜索特征代码中出现了ordchr^(XOR)|% 这些是典型的手工加密操作。hashlib.md5等是哈希通常不可逆但可能用于比较。类比已知密码维吉尼亚密码、栅栏密码、培根密码等是CTF常客。将你的输入输出对与这些经典密码的特征对比。7.3 本地环境与远程题目差异问题本地利用成功但打远程服务器没反应或报错。排查路径差异Linux和Windows路径分隔符不同。你的../../app.py在Windows本地Docker里可能有效但远程Linux服务器的工作目录结构可能不同。尝试更多层的../。过滤规则差异远程服务器可能有额外的WAFWeb应用防火墙规则。尝试更隐蔽的payload或者使用其他等效的漏洞利用方式比如本题可能还有其他入口点。网络问题检查你的payload是否被浏览器或Burp Suite自动编码了。最好使用Burp Repeater模块手动发送原始HTTP请求。7.4 工具使用心得Burp Suite是你的主力别只用浏览器。用Burp抓包、改包、重放Repeater、爆破Intruder。特别是Intruder在测试文件包含路径、模糊参数时无比强大。Python是你的瑞士军刀快速编写解密脚本、生成payload、自动化请求。requests库必须熟练掌握。Docker是你的沙盒任何不确定的操作先在本地Docker环境测试。别怕把容器搞崩docker rm -f删掉重来就是。8. 防御视角如何避免此类漏洞作为开发者了解攻击手段是为了更好地防御。针对这道题体现的漏洞防御文件包含绝对路径白名单不要使用用户输入直接拼接路径。应该预先定义好允许访问的文件列表白名单用户只能选择列表内的项。使用安全的APIFlask的send_from_directory函数在正确使用时是安全的但必须确保其第一个参数目录是固定的、不允许用户控制的。如果需要动态目录必须进行严格的规范化os.path.normpath和前缀检查确保路径不会跳出安全基目录。禁用危险函数在PHP中可以关闭allow_url_include。在Python中避免使用eval()、exec()或能动态执行代码的函数处理用户输入。防御自定义加密漏洞不要自己造轮子对于需要安全性的场景如用户密码、会话令牌务必使用业界标准、经过严格审计的加密库和算法如Python的cryptography库并使用安全的操作模式。密钥管理密钥决不能硬编码在代码中。使用环境变量或专业的密钥管理服务KMS并确保其有足够的熵随机性。如果必须自定义比如业务逻辑需要一种可逆的混淆请明确告知这不是用于安全加密并且最好让安全团队进行评审。攻克这道“黑客密室逃脱”题目的过程是一次完整的微型渗透测试演练信息收集 - 漏洞发现与利用 - 权限提升/关键信息获取 - 达成目标。它清晰地展示了Web安全中“漏洞链”的思想。Flask文件包含是你的敲门砖而逆向自定义加密算法则是打开最终宝箱的钥匙。掌握了这两个核心技能你就已经推开了CTF Web世界的大门。接下来你可以去尝试更多包含文件上传、SQL注入、模板注入SSTI的题目将这些技能组合运用你会发现那些看似复杂的系统往往都是由一个个基础的不安全点构成的。
从蓝桥杯Web题实战解析Flask文件包含与加密逆向
1. 项目概述从一道蓝桥杯Web题切入CTF实战如果你对网络安全感兴趣或者听说过CTFCapture The Flag夺旗赛但觉得它高深莫测那么这篇文章就是为你准备的。我们不谈那些复杂的底层协议和汇编指令就从一道非常经典的、来自蓝桥杯的Web题目“黑客密室逃脱”开始。这道题完美地融合了两个在CTF Web方向中极为常见的考点Flask框架下的文件包含漏洞和自定义加密算法的逆向分析。对于新手来说它就像一座精心设计的“密室”既有明确的线索漏洞点又有需要动脑破解的“锁”加密逻辑。通过拆解这道题你不仅能亲手拿到Flag比赛中的目标字符串更能透彻理解这两个漏洞的原理、利用方法以及背后的安全思想。无论你是计算机专业的学生还是希望转行安全领域的开发者甚至是单纯对“黑客技术”感到好奇的爱好者这篇指南都将带你跨出从理论到实战的关键一步。2. 核心漏洞原理深度解析在动手解题之前我们必须先搞清楚要面对的是什么。题目基于Flask框架这决定了我们的攻击面漏洞点是文件包含这是我们突破的入口而自定义加密则是我们获取最终Flag前必须解开的谜题。2.1 Flask框架与潜在的风险点Flask是一个轻量级的Python Web框架以其灵活和简洁著称。开发者通过定义路由app.route和处理函数来构建应用。在本题中风险往往源于开发者对用户输入过于信任。例如一个常见的危险操作是使用render_template函数或send_from_directory函数时直接拼接了用户可控的变量。想象一下如果代码中有一行类似send_from_directory(‘./templates‘, filename)的语句而filename这个参数完全由用户通过URL参数如?filexxx控制那么危险就产生了。攻击者可以通过构造特殊的filename值如../../etc/passwd让服务器读取并返回本不应被访问的系统文件。这就是路径遍历攻击是文件包含漏洞的一种常见形式。Flask本身并不“脆弱”脆弱的是开发者不安全的使用方式。2.2 文件包含漏洞LFI的攻防本质文件包含漏洞尤其是本地文件包含Local File Inclusion, LFI允许攻击者通过Web应用动态包含服务器本地的文件。其危害极大因为攻击者可能读取到配置文件如/etc/passwdLinux用户信息、/proc/self/environ进程环境变量可能包含密钥。源代码通过包含.py文件或利用PHP等语言的特性本题是Flask但原理相通来获取应用逻辑。日志文件在特定条件下向日志中写入恶意代码再包含该日志文件以执行代码。在CTF中LFI的利用常常是为了获取源代码从而发现更多的漏洞线索比如本题中的加密逻辑。防御的关键在于对用户输入进行严格的过滤和校验比如限制包含的文件路径必须在某个安全目录内或使用白名单机制。2.3 自定义加密CTF中的“锁匠”挑战CTF题目很少使用标准的、强加密算法如AES因为那对于解题来说往往意味着暴力破解缺乏技巧性。出题人偏爱自定义加密或弱加密。这种加密可能只是简单的字符替换如凯撒密码、Base64变种、逻辑运算XOR或者是几种简单操作的组合。解题者的任务就是扮演“锁匠”通过分析有限的加密/解密样本通常是题目给出的输入输出对逆向推断出加密算法的逻辑。这需要一定的观察力、逻辑思维和编程能力。在本题中我们最终需要逆向的很可能就是一个用于验证身份或生成关键信息的自定义函数。3. 靶场环境搭建与题目复现“纸上得来终觉浅绝知此事要躬行。” 要真正学会最好的方法就是自己动手把题目跑起来。3.1 使用Docker快速构建漏洞环境对于CTF学习我强烈推荐使用Docker。它能让你的实验环境与主机隔离避免搞乱系统并且一键部署极其方便。准备Dockerfile如果题目方没有提供现成的镜像我们需要根据题目描述或逆向得到的源码编写Dockerfile。一个典型的用于Flask题目的Dockerfile如下FROM python:3.9-slim WORKDIR /app COPY requirements.txt . RUN pip install --no-cache-dir -r requirements.txt COPY . . CMD [“python”, “app.py”]这里基于Python 3.9精简镜像将工作目录设为/app复制依赖文件并安装最后复制所有应用代码并启动。编写requirements.txt这个文件列出了项目依赖。flask2.0.1构建与运行# 在包含Dockerfile和app.py的目录下执行 docker build -t ctf-flask-lfi . docker run -p 8080:8080 --name my-ctf-challenge ctf-flask-lfi现在访问http://localhost:8080就能看到题目界面了。注意在真实CTF或蓝桥杯比赛中题目是远程在线提供的。本地搭建是为了方便我们反复调试、深入分析尤其是查看服务端打印的调试信息这在远程环境中是不可能的。3.2 题目初步信息收集启动环境后第一步不是盲目测试而是进行“侦察”。前端观察打开网页查看所有可见的链接、表单、按钮和注释CtrlU查看网页源代码。寻找任何提示比如注释里可能写着!-- debug: source code in /source --。目录扫描使用工具如dirsearch或gobuster进行简单的目录爆破寻找常见的备份文件、源码文件或管理界面。dirsearch -u http://localhost:8080 -e php,py,txt,bak,zip,tar.gz可能会发现/app.py/www.zip/source等线索。参数探测观察URL。如果看到类似?pageabout.html这样的参数立即警觉这很可能就是文件包含的点。尝试修改为?page../../../../etc/passwd进行测试。4. 漏洞利用文件包含实战突破假设通过信息收集我们发现了URL中存在一个file参数用于加载模板http://localhost:8080/show?filewelcome.html。4.1 基础路径遍历测试我们的目标是读取应用的源代码app.py因为加密逻辑一定写在里面。尝试直接读取?fileapp.py。如果直接返回了代码那题目就太简单了。通常会有路径限制。使用路径遍历?file../../app.py。这里../表示上一级目录。我们需要猜测应用当前的相对路径。假设Flask应用从/app目录运行模板在/app/templates那么../../就能退回到根目录再进入/app。使用绝对路径在某些配置下可以直接使用绝对路径如?file/app/app.py。利用PHP包装器非本题但重要如果是PHP环境php://filter协议是神器可以读取文件源码并进行Base64编码输出避免代码被直接执行。例如?filephp://filter/convert.base64-encode/resourceindex.php。但在纯Flask/Python环境下这个技巧无效。4.2 进阶技巧利用Flask特性获取源码在无法直接穿越目录时我们需要更巧妙的思路。Flask在调试模式下如果触发服务器错误会返回一个包含错误信息和局部变量值的交互式调试页面。虽然生产环境会关闭它但CTF题有时会开启。我们可以尝试触发一个错误比如传入一个不存在的文件名或者利用参数类型错误让错误信息泄露部分代码栈信息。但这方法不稳定。更可靠的方法是如果文件包含点能读取到Python的临时文件或被导入的模块文件吗这通常很难。在本题“黑客密室逃脱”的典型设定中突破口往往是一个“源码泄露”。例如通过?file....//....//....//app.py这样的多重URL编码../编码为%2e%2e%2f绕过简单的过滤或者题目本身就预留了一个路由/source或/debug来直接显示源码。作为新手一定要养成检查常见源码泄露路径的习惯。假设我们通过?file....//....//app.py成功读取到了app.py的源代码。接下来就是代码审计时间。5. 代码审计与加密逻辑逆向拿到源代码后我们就像拿到了密室的建筑图纸。快速浏览代码寻找几个关键部分路由定义所有app.route的地方特别是处理我们刚才利用的file参数的路由。加密/解密函数寻找名为encryptdecryptcryptocheck_token等的函数或者涉及hashlib、异或^运算、字符循环移位等操作的自定义函数。Flag生成或输出逻辑寻找像flagFLAGsecret这样的变量或者最终输出Flag的条件语句。5.1 分析示例加密函数假设我们在app.py中找到了如下函数def weird_encrypt(text): key “SECRET_KEY_HERE“[:len(text)] result ““ for i, c in enumerate(text): result chr((ord(c) ord(key[i]) - 2*ord(‘A‘)) % 26 ord(‘A‘)) return result这是一个典型的流加密逐字符加密。我们来逆向分析key被截取成和明文一样长。对明文的每个字符c和密钥对应字符key[i]进行运算(ord(c) ord(key[i]) - 2*ord(‘A‘)) % 26 ord(‘A‘)。ord(‘A‘)是65。这个运算的本质是将字符c和key[i]都视为0-25的数字A0, B1, ... Z25然后相加后取模26再转换回字符。这实际上是**维吉尼亚密码Vigenère cipher**的一种变体解密过程就是逆运算chr((ord(c_encrypted) - ord(key[i]) 26) % 26 ord(‘A‘))。5.2 寻找密钥与构造解密器现在我们知道它是维吉尼亚密码但密钥key是什么继续审计代码。密钥可能硬编码在代码里也可能来自某个文件我们之前用LFI读到的/proc/self/environ或配置文件或者通过某个路由计算出来。假设我们在另一个路由/get_key中发现返回了密钥的Base64编码。或者密钥就是SECRET_KEY_HERE。那么我们就可以编写Python解密脚本了。def weird_decrypt(enc_text, key): key key[:len(enc_text)] result ““ for i, c in enumerate(enc_text): # 逆向运算加密是 (p k) % 26 解密就是 (c - k 26) % 26 p (ord(c) - ord(‘A‘) - (ord(key[i]) - ord(‘A‘)) 26) % 26 result chr(p ord(‘A‘)) return result # 假设我们从题目响应中获取了密文和密钥 ciphertext “LXFOPVEFRNHR“ # 示例密文 key “SECRET“ plaintext weird_decrypt(ciphertext, key) print(plaintext) # 输出解密结果6. 整合利用链获取最终Flag通常CTF题的Flag不会直接放在一个能被LFI读取的文本文件里。它需要我们将前几步串联起来形成一个完整的利用链。一个典型的流程可能是利用LFI读取/app/app.py 获得源代码。审计代码发现访问/flag路由需要提供一个有效的token。分析token的生成算法。代码显示token encrypt(username “|“ timestamp) 其中encrypt就是我们刚才分析的自定义函数。寻找密钥。代码中可能写死了密钥或者密钥来自环境变量。我们可以尝试用LFI读取/proc/self/environLinux下进程环境变量文件里面可能包含SECRET_KEYxxxxx。伪造token。知道了加密算法和密钥我们就可以为任意用户名和时间戳生成合法的token。通常题目要求管理员用户比如usernameadmin。构造请求。带着伪造的token访问/flag路由服务器验证通过返回Flag。import requests import time BASE_URL “http://localhost:8080“ # 1. 读取源码假设漏洞点 source_code requests.get(f“{BASE_URL}/show?file....//....//app.py“).text print(“[] Source code obtained.“) # 此处省略代码解析和密钥提取过程假设我们已得到密钥 MY_SECRET_KEY KEY “MY_SECRET_KEY“ # 2. 根据加密算法生成token def generate_token(username): timestamp int(time.time()) plain f“{username}|{timestamp}“ token weird_encrypt(plain, KEY) # 使用前面分析出的加密函数 return token # 3. 以admin身份请求flag admin_token generate_token(“admin“) flag_resp requests.get(f“{BASE_URL}/flag“, cookies{“token“: admin_token}) # 或者可能是POST请求token在参数里 # flag_resp requests.post(f“{BASE_URL}/flag“, data{“token“: admin_token}) print(“[] Flag response:“, flag_resp.text) # 在响应中寻找类似 flag{...} 格式的字符串7. 常见问题与调试技巧实录在实际操作中你一定会遇到各种问题。下面是我踩过的一些坑和总结的技巧。7.1 文件包含漏洞利用失败问题../被过滤或转义了。排查尝试URL编码..%2f(/的编码)%2e%2e%2f(../的编码)。尝试双重编码%252e%252e%252f对%2e的%再次编码。尝试绝对路径/etc/passwd。尝试空字节截断在较老版本PHP中有效Python/Flask中通常无效../../etc/passwd%00。查看服务器返回的错误信息可能提示了过滤规则。心得永远不要只试一种payload。准备一个payload字典用Burp Suite的Intruder模块进行模糊测试效率最高。7.2 加密算法逆向困难问题加密函数逻辑复杂一眼看不出是什么。排查黑盒测试如果题目提供加密接口输入有规律的数据如‘A‘*10‘ABCDEFG‘观察输出。这能帮你判断是分组加密还是流加密是否有移位、替换等。静态分析在代码中给加密函数插入print语句在本地复现的环境里打印中间变量值。这是最有效的方法。搜索特征代码中出现了ordchr^(XOR)|% 这些是典型的手工加密操作。hashlib.md5等是哈希通常不可逆但可能用于比较。类比已知密码维吉尼亚密码、栅栏密码、培根密码等是CTF常客。将你的输入输出对与这些经典密码的特征对比。7.3 本地环境与远程题目差异问题本地利用成功但打远程服务器没反应或报错。排查路径差异Linux和Windows路径分隔符不同。你的../../app.py在Windows本地Docker里可能有效但远程Linux服务器的工作目录结构可能不同。尝试更多层的../。过滤规则差异远程服务器可能有额外的WAFWeb应用防火墙规则。尝试更隐蔽的payload或者使用其他等效的漏洞利用方式比如本题可能还有其他入口点。网络问题检查你的payload是否被浏览器或Burp Suite自动编码了。最好使用Burp Repeater模块手动发送原始HTTP请求。7.4 工具使用心得Burp Suite是你的主力别只用浏览器。用Burp抓包、改包、重放Repeater、爆破Intruder。特别是Intruder在测试文件包含路径、模糊参数时无比强大。Python是你的瑞士军刀快速编写解密脚本、生成payload、自动化请求。requests库必须熟练掌握。Docker是你的沙盒任何不确定的操作先在本地Docker环境测试。别怕把容器搞崩docker rm -f删掉重来就是。8. 防御视角如何避免此类漏洞作为开发者了解攻击手段是为了更好地防御。针对这道题体现的漏洞防御文件包含绝对路径白名单不要使用用户输入直接拼接路径。应该预先定义好允许访问的文件列表白名单用户只能选择列表内的项。使用安全的APIFlask的send_from_directory函数在正确使用时是安全的但必须确保其第一个参数目录是固定的、不允许用户控制的。如果需要动态目录必须进行严格的规范化os.path.normpath和前缀检查确保路径不会跳出安全基目录。禁用危险函数在PHP中可以关闭allow_url_include。在Python中避免使用eval()、exec()或能动态执行代码的函数处理用户输入。防御自定义加密漏洞不要自己造轮子对于需要安全性的场景如用户密码、会话令牌务必使用业界标准、经过严格审计的加密库和算法如Python的cryptography库并使用安全的操作模式。密钥管理密钥决不能硬编码在代码中。使用环境变量或专业的密钥管理服务KMS并确保其有足够的熵随机性。如果必须自定义比如业务逻辑需要一种可逆的混淆请明确告知这不是用于安全加密并且最好让安全团队进行评审。攻克这道“黑客密室逃脱”题目的过程是一次完整的微型渗透测试演练信息收集 - 漏洞发现与利用 - 权限提升/关键信息获取 - 达成目标。它清晰地展示了Web安全中“漏洞链”的思想。Flask文件包含是你的敲门砖而逆向自定义加密算法则是打开最终宝箱的钥匙。掌握了这两个核心技能你就已经推开了CTF Web世界的大门。接下来你可以去尝试更多包含文件上传、SQL注入、模板注入SSTI的题目将这些技能组合运用你会发现那些看似复杂的系统往往都是由一个个基础的不安全点构成的。