MikroTik认证被揭发

2022-02-15 20:40:28

2019年8月,MikroTik发布了6.45.1版RouterOS软件更新,删除了升级到新固件的所有路由器上的明文密码存储。在增强路由器安全性的同时,这对使用MikroTik专有协议(如MAC Telnet和Winbox)的定制工具的研究人员、网络管理员和修补者来说是一个打击。尽管用户请求协助,MikroTik仍未能详细说明新的认证程序。Margin Research很高兴能够阐明身份验证过程,并为Winbox和MAC Telnet身份验证提供Python概念验证(POC)实现。

米克罗蒂克';s的新身份验证过程使用了安全远程密码(SRP)的变体。SRP是一种密码认证密钥交换协议,它将密码合并到密钥交换计算中。计算共享机密需要知道正确的密码,因此相同的机密表示身份验证成功。SRP规范可以追溯到20多年前,在最近的过去,主流使用获得了牵引力,其在OpenSSL中的使用突出了这一点。然而,MikroTik没有实现这个SRP协议。相反,RouterOS使用椭圆曲线SRP(EC-SRP),特别是EC-SRP5。该协议的流行程度要低得多,其定义顺序如下:

路由器生成一个16字节的用户salt,并根据等式v=ECDH(SHA2(salt | SHA2(username |“:“| password))[1]计算用户的密码验证器v

路由器将用户名salt和v的x坐标vx存储在/rw/store/user的内存中。dat

客户端生成临时私钥Tc,并计算其临时公钥Wc=ECDH(Tc)。客户端发送一个身份验证请求,包括用户名和点的x坐标Wc x,作为其临时公钥,因为每个椭圆曲线x坐标有两个y解(x,y)和(x,-y),客户端还传输生成点的y坐标Wc y的奇偶校验,以确保服务器计算相同的点,而不是其否定

服务器检索相关客户端的salt和Vx。然后,服务器生成临时私钥Ts,并计算密码纠缠的公钥点Ws=ECDH(Ts)+plot(SHA2(Vx))[2]。最后,服务器用Ws-x和salt进行响应。服务器同样计算并传输其公共点的y坐标Ws-y的奇偶性

客户机现在知道了用户的salt和服务器的公钥,可以按如下方式计算共享密钥和确认码:计算v';s私钥,vp=SHA2(salt | SHA2(用户名|“:“|密码))

计算共享点z,使用椭圆曲线与之前计算的u点相乘,以找到z=u(Tc+h.v)

服务器计算共享秘密点z,如下所示:使用服务器的私钥执行最终的椭圆曲线标量乘法,以产生z=Ts(Wc+h.v)

服务器通过类似地计算Cc并检查客户端提供的值来验证用户名和密码。[3]

一旦确认了一个等效的共享秘密,服务器和客户端就可以对数据进行加密。MikroTik采用MAC-then加密策略,利用AES-CBC作为加密算法,HMAC作为身份验证算法。RouterOS还为HMAC和AES使用单独的发送和接收密钥,下面标记为AES s、AES r、HMAC s、HMAC r。服务器和客户端都使用“魔术”字符串和HMAC密钥派生函数HKDF生成这些密钥。消息使用AES-CBC模式中使用的唯一随机初始化向量IV预先发送加密数据。

这无疑是一个复杂的过程,涉及的步骤比标准的椭圆曲线Diffie-Hellman或以前的RouterOS协议(它们只是检查密码散列)多得多。但困难并不止于此;这个协议由于MikroTik的椭圆曲线选择而变得更加复杂。RouterOS身份验证使用标准的蒙哥马利曲线(如流行的Donna2519库)进行某些计算,但不是全部。不幸的是,它没有使用NaCl/LiB默认的Ed25519 Edwards曲线。相反,为了提高效率或模糊度(或两者兼而有之),RouterOS在标准Weierstrass曲线上执行大多数计算:Y 2=X 3+aX+b。此外,它计算加权投影空间P(2,3,1)中的点,以获得更高的计算效率。这就产生了Weierstrass方程:y2=x3+axz4+bz6,其中y=y/z3和x=x/z2。

困惑的这是可以理解的。前面详细介绍的所有内容的结果都是一个认证协议,其中包含三种不同曲线类型的大量椭圆曲线计算:蒙哥马利曲线、仿射形式的Weierstrass曲线(Z=1)和加权投影空间中的Weierstrass曲线。这需要在不同的曲线和投影空间之间进行转换,这使得遵循身份验证流程非常困难。Python POC示例详细介绍了该序列,不过下面的高级概述可能更适合一些感兴趣的读者:

ECDH()方程通过将私钥priv乘以加权射影空间中Weierstrass曲线上的基点g来生成公钥pub。这将返回点(xw:yw:zw)。然后,该函数将点转换为Weierstrass仿射形式,并进一步转换为Montgomery形式;具体来说,该函数计算Weierstrass仿射坐标X=X/z 2,并将X转换为蒙哥马利形式。这很奇怪,因为私钥在Weierstrass曲线上相乘,但返回的公钥是蒙哥马利形式的X坐标

函数的作用是:在Weierstrass曲线上以仿射形式绘制给定的x坐标。因此,它返回一个Weierstrass点(X:Y:1)。有趣的是,它实际上是通过首先在蒙哥马利曲线上绘制该点并通过添加常数a/3(其中a是曲线方程Y 2=X 3+aX 2+X中的蒙哥马利曲线常数)来转换X坐标来执行此操作的

Weierstrass曲线上的所有点乘和加法都是在加权投影空间中进行的。因此,任何返回的参数(例如,共享秘密点z、公钥Wc和Ws)都必须转换为Weierstrass仿射形式

考虑到这些因素,情况变得更清楚了。使用Weierstrass曲线进行公钥计算的微妙选择使得一个模糊的协议更难复制。考虑到所概述的所有复杂性,毫不奇怪,直到现在,这种身份验证方案还没有在公共实现中复制。

我们希望如此。这项加密逆向工程的工作包含了一点所有内容:一个模糊的协议、多个椭圆曲线定义,以及从加权投影空间进行的转换。如果你渴望得到更多,或者想让自己经受进一步的技术折磨,请参阅我们GitHub repo中的源代码和附加注释。但是等等!对于那些真正贪得无厌的人来说';还有更多。我们在逆向工程中使用的最好的资源是一个未完成的IEEE提交草案,这是由回程机器提供的。事实上,米克罗蒂克';其执行情况与草案几乎相同';他提议的协议。看看你是否能发现细微的差别,并惊叹(就像我们所做的那样)共享的秘密仍然是一样的。

[1] ECDH()接受私钥作为输入,并返回相关的椭圆曲线公钥,如椭圆曲线Diffie-Hellman。这是通过椭圆曲线中的gen_公钥方法复制的。py的WCurve课程

[2] plot()接受x坐标并返回椭圆曲线上的对应点。在椭圆曲线中,lift_x方法可以复制这一点。py的WCurve课程

[3] 服务器可以通过向客户端发送服务器确认码Cs来完成认证握手,以验证服务器的真实性。在Winbox协议的情况下,Cs=SHA2(h+Cc+zx)