研究人员: Alexey Bukheyev和Aliaksandr Chailytko
ISPsystem面板是一个众所周知的软件,具有用户友好的Web界面,用于管理Web服务器,专用服务器,VPS(虚拟专用服务器)和计费。ISPsystem软件产品被全球数百家托管服务提供商使用,包括1Cloud,King Servers和Ru-Center。ISP系统产品安装量超过10,000个:
图1:估算ISPmanager安装的数量。
最着名的ISPsystem产品是:
- ISPmanager:Web托管和Linux服务器控制面板(类似于cPanel)。
- BILLmanager:一体化网络托管计费软件。
- DCImanager:专用服务器配置工具包。
- VMmanager:服务器虚拟化管理软件。提供两种选择:适用于OpenVZ和KVM虚拟化类型。
在本文中,我们描述了我们如何在ISPsystem软件中发现一个关键的安全漏洞,它允许攻击者劫持另一个登录用户的会话并控制该用户的网站,虚拟机,计费数据等。所有ISP系统产品使用相同的核心,它们同样受此漏洞的影响。
幸运的是,ISPsystem支持快速响应我们的漏洞报告,并修复了版本5.178.2中的漏洞。
ISPsystem允许用户免费下载和设置他们的软件。要使用该软件,您必须购买许可证,但可以获得有限的试用许可证。我们下载并安装了一个用于VPS管理的ISPsystem面板实例:
图2: VMmanager安装。
该脚本设置必要的环境,包括MYSQL数据库服务器和HTTP服务器。默认情况下,HTTP服务器在1500 TCP端口上运行。
图3: VMmanager HTTP服务器进程。
完成必要的设置步骤后,我们可以通过Web浏览器访问该面板。这是登录屏幕:
图4: VMmanager面板登录界面。
现在,我们可以在本地进行实验,而不会影响托管服
认证过程
我们来看看身份验证过程。使用以下HTTP POST请求执行身份验证:
图5: VMmanager HTTP身份验证请求。
身份验证成功后,服务器会设置会话cookie,这是一个保存在Web浏览器存储中的唯一字符串。会话cookie使系统能够识别用户,而无需每次都请求用户名和密码。会话cookie的名称取决于产品名称,由两部分组成:产品名称(如“ vmmgr ”或“ vemgr”)和“ ses5 ”。在我们的例子中,会话cookie名称是“ vmmgrses5 ”。另一个cookie“vmmgrlang5”用于为用户界面选择模板和语言。
图6: VMmanager成功的身份验证响应。
我们可以看到,cookie的值是一个6字节的HEX编码字符串(该字符串总是包含12个字符,即[0-9a-z])。Cookie到期日期将在未来设置为一年。
因此,攻击者只需要选择正确的6字节值来劫持另一个用户的有效会话。仅存在256 6为会话标识符可能的组合。
实际上,对于远程暴力攻击来说,数字256 6仍然非常庞大。因此,我们决定看看是否可以减少值的范围。
为此,我们需要知道会话cookie生成算法。
业务逻辑以C ++实现。特别是,诸如数据库操作,用户认证和用户会话管理之类的操作由在ihttpd进程的上下文中执行的C ++代码执行。
由于我们需要找到生成cookie会话的位置,我们在二进制文件中查找文本字符串“ses5”,并在以下库中找到它:
- /usr/local/mgr5/lib/libispapi.so
- /usr/local/mgr5/lib/libmgr.so
- /usr/local/mgr5/lib/libispcgi.so
- /usr/local/mgr5/lib/libostemplate.so
- /usr/local/mgr5/libexec/ihttpd.so
在对上述文件进行简要回顾后,我们发现密码验证由libispapi.so库执行:
在身份验证过程中,将创建isp_api :: Session类中的新对象:
图7:反编译认证例程的一部分:创建Session类的实例
最后,调用isp_api :: Authen :: Data :: generate_id例程来生成会话标识符。实际上,在这个例程中我们可以看到以下代码:
图8:生成会话cookie的值。
如上所述,会话标识符的长度恰好是6个字节。相同的数字从libmgr.so库传递给str :: Random例程。我们需要找到的最后一件事是str :: Random实现。不应将此函数与库函数std :: rand混淆,因为它们具有完全不同的实现。
要生成随机字节序列,rand()函数用于str :: Random方法:
图9: str :: Random实现的一部分:生成随机序列。
要生成长度为N的随机字符串,rand()函数将被调用N次。此调用的结果将分配给“char”类型的变量。因此,rand()函数产生的值被裁剪为8位的长度。此时,我们应该注意到rand()函数不会生成真正的随机数。相反,该函数实现了伪随机数生成算法。
一个重要的是由伪随机生成器产生的序列完全由其初始状态确定,也称为种子。因此,对于相同的种子,一系列伪随机数总是相同的。下图描述了str :: Random方法如何生成会话cookie:
图10:示例:使用str :: Random生成会话cookie。
在我们的例子中,每次只有在生成少于400个伪随机值之后才设置新种子。我们还应该强调种子是一个32位整数。让我们看一下str :: Random函数实现中负责设置随机种子的部分:
图11: str :: Random实现的一部分:设置随机种子。
在上面的伪代码中,g_rnd_reset_counter变量用于确定何时应更新伪随机数生成器的种子。g_rnd_reset_counter的初始值设置为rand()%255 + 128。也就是说,此变量可以取128到382之间的值。每次调用str :: Random方法时,都会从g_rnd_reset_counter变量中减去生成的随机字符串的长度。当此变量小于或等于0时,将重置发生器的种子。
str :: Random的这种实现使得可以确定用于已知会话cookie的伪随机生成器初始化的最后一个种子值。我们可以通过简单地查找伪随机生成器为每个可能的种子值生成的短序列中的会话cookie来实现这一点。
图12:种子查找过程的说明。
如果我们知道会话cookie,我们可以计算出生成器的种子值,并预测生成器为该种子生成的整个序列。
因此,如果另一个用户在我们获得会话cookie后登录,我们可以使用最多382次尝试的暴力攻击来获取他的会话cookie。如果用户在我们获得会话cookie之前就已登录,则会出现类似情况。两种情况都显示在下一张图片上:
图13:伪随机会话标识符预测。
可能的攻击场景
在可能的攻击情形中,攻击者遵循以下步骤:
- 进入时间段“T”后,使用有效的用户名和密码登录,并保存指定的会话cookie的值。
- 使用rand函数为0到2 32的所有种子生成382字节值的数组,并在生成的数组中搜索保存的会话cookie序列(应该强调的是,必须使用与rand函数相同的精确实现,如同攻击系统)。
- 从种子的382字节数组中提取所有6字节子序列,其中找到已知的会话cookie。
- 尝试使用所有提取的6字节子序列登录会话cookie。
- 如果另一个用户在攻击期间登录,他的会话将被劫持。
时间段“T”应该足够小,以确保我们为发生器使用的每个新种子获得至少一个会话cookie。“T”的最佳值取决于一天中的时间和活动用户的数量。我们还需要考虑从其他地方调用rand()。因此,如果有许多活动用户,则应减少周期T.
对于这种情况,6字节序列的种子查找在16核CPU上最多需要20分钟,并且可以轻松地缩放此操作以实现任何所需的速度。您还可以预生成所有2 32个序列并将它们存储在数据库中。它需要大约1.5 TB的空间来存储所有生成的数据。因此,有几种方法可以通过已知的生成序列实时确定种子。在获取种子和字节序列之后,应该将所有6字节子序列应用为可能的会话cookie。
您还可以从计算序列的开头计算已知会话cookie的偏移量。如果没有登录用户,则偏移之间的距离是恒定的。如果其他用户登录,则距离会增加。
攻击的第一步是使用Python和urllib2库实现的。以下选项用于登录受攻击的面板:
图14:利用PoC:创建登录请求并建立HTTPS连接(Python)
会话标识符从“ vemgrses5 ”cookie获取:
图15:利用PoC:检索会话cookie值(Python)
首先,我们执行脚本以检查在执行单个登录操作且没有其他活动用户时查询rand()的频率。
为了找出适合脚本获取的会话标识符的种子值,可以使用以下C代码:
图16:利用PoC:生成具有特定种子的随机数序列(C,Linux)
上面的代码设置指定的种子并生成一个伪随机序列,在该序列中应搜索已知的会话cookie。使用函数srandom_r()和random_r()代替srand和rand以使此代码能够在多个线程中并行运行。
下表显示了我们获得的结果:
图17:在生成的序列中找到会话标识符及其偏移量。
列会话cookie包含由服务器为每个成功的登录尝试返回“vmmgrses5”标识。Found种子列包含我们为相应会话cookie 找到的种子值。所有会话cookie都属于使用相同种子生成的伪随机序列。列Offset显示从伪随机序列开始的偏移量。最后一列显示随机序列中邻居会话标识符之间的距离。
我们可以看到,生成序列中获取的会话cookie(6字节数组)的偏移量之间的距离始终为14.这意味着对于每次成功登录尝试,rand()通常被调用14次:6次生成会话cookie字符串,和其他地方8次。因此,如果距离变得超过14,则存在另一个活动用户。
在脚本执行期间,我们使用浏览器执行了登录尝试。服务器将vemgrses5 = 9e723afa5922 cookie 分配给我们的会话:
图18:来自VMmanager服务器的HTTP响应的头部。
接下来,我们展示了此会话cookie也是可预测的。
对于脚本获取的会话cookie,我们在实验期间得到了以下结果:
图19:演示:已知会话标识符的种子查找结果
从10:57:56到10:58:17的时间段内的偏移之间的距离增加了。这个时间与用户活动的时间一致。因此,通过检查距离,我们可以确定其他用户在网站上的活动。
让我们看一下使用找到的种子0x747777E4生成的伪随机序列,该种子在那个时期使用:
图20:演示:预测的伪随机序列包含有用的标识符
我们可以看到,用户的会话cookie存在于生成的序列中。脚本获取的已知值以绿色突出显示; 我们预测的值以红色突出显示。
我们需要做的最后一件事就是在距离大于14的已知值之间强制生成序列的所有6字节子序列:
图21:演示:蛮力攻击的数据
在这种情况下,只需要检查66个值以查找另一个用户的会话cookie的正确值。
最后,因为具有默认设置的服务器与具有会话cookie的远程主机的IP地址不匹配,所以我们能够使用以下请求以及被盗会话ID来入侵另一个用户的会话:
图22:演示:请求劫持会话
我们可以看到,攻击可以由具有合理数量资源的个人轻松实施。
受影响的ISP系统产品的完整列表:
- ISP系统ISPmanager
- ISPsystem BILLmanager
- ISPsystem DCImanager
- ISP系统VMmanager
- ISPsystem DNSmanager
- ISPsystem IPmanager
- ISPsystem COREmanager
如果您使用的任何列出的ISPsystem产品的核心版本低于5.178.2,我们建议您尽快升级。
Check Point的防止这些漏洞的IPS签名是“ ISPsystem COREmanager Authentication Bypass ”。
本文作者为Mr.Bai,转载请注明。