原文:
https://laconicwolf.com/2018/09/21/mfa-bypass-and-privilege-escalation/
本文主要讲解两个MFA(多因素验证)应用在web应用程序中部署实现时存在的问题。MFA的确是非常好的,我非常支持它,但在很多应用系统中,第二个因素的验证与第一个因素无关,这导致了可以将帐户“A”的用户名/密码与账号“B”的第二个因素混合。在第一个MFA应用中,导致可以绕过第二个因素。在第二个MFA应用中,导致了权限提升。
我们先来走一遍该系统的正常身份验证流程,然后再来讨论这些漏洞。
正常身份验证流程
使用用户名和密码登录,如图:
服务器检查用户名/密码是否正确,返回第二个因素要提交的必要数据,这些数据具体来说就是状态令牌,oktaUserId和factorId:
在上述响应之后,将自动提交一个请求以启动第二个因素的SMS通知,然后你会看到如下的提示:
提交第二个因素并确认后,会自动发起第二个身份验证请求,如图:
服务器验证你的凭证,如果凭证有效,会返回JWT(json web token)响应,这样你就可以访问应用程序了。
漏洞
使用MFA的应用对无效的用户名/密码的不断尝试并没有严格的账户锁定策略。这个应用只是通过JavaScript向你显示锁定警告,但在服务器后端却没有进行逻辑验证,刷新页面后,锁定警告就消失了。我将身份验证请求发送到repeater中,并且在进行正确的身份验证之前故意多次尝试错误的用户密码,发现并没有锁定账户。
没有账号锁定就太好了,不过,即使我们可以暴力破解出密码,我们仍然要考虑第二个因素。幸运的是,该应用对MFA和身份验证请求是独立验证的。
于是我就执行了下列操作:
没有帐户锁定,我能够暴力破解出另一个用户的密码。我已经在该系统上有一个有效的帐户(可以自行注册),所以我用初始用户名/密码进行登录(服务器返回了stateToken和factorId),提交了SMS MFA码,然后拦截第二个用户名/密码身份验证请求,进行暴力破解得到正确的用户和密码,替换掉我的用户名和密码 ,如图:
然后,服务器返回了一个JWT响应,这样我就能够以第二个用户的身份访问应用了,如图:
使用用户名密码登录后,hidUserId和hidMdaId值存在于响应包中,然后进入到下一步,需要我进行第二个因素验证,如图:
security code(安全码)与hidUserId和hidMfaId一起提交,如果安全码正确,则授予访问权限,如图:
漏洞
与第一个系统类似,此应用程序将MFA作为两个独立的步骤来处理。第一个请求验证用户名/密码并返回了防篡改的hidUserId和hidMfaId,第二个请求验证了安全码。我注意到这个应用程序的问题是,当提交安全码时,hidUserId也会被提交。我开始琢磨我是否可以替换为另一个有效的hidUserId并冒充该用户。不过,这里有个问题,就是hidUserId是一个防篡改的字符串,我无法获取到或也无法猜到它的值。
凑巧的是,这个应用程序还有另一个漏洞,让我能够获得该值。
下面就是我所操作的:
如果我使用一个有效用户名和无效密码进行登录,那么应用程序就不会返回hidUserId,但是状态会改变,当我再次尝试登录时(使用相同的有效用户名和无效密码),hidUserId将会动态生成并且在请求中提交。有了这个漏洞,我就能得到任何用户的hidUserId,所以我选择了一个管理员账户,如图:
现在测试是否可以在普通用户的有效身份验证请求中替换成admin用户的hidUserId。所以我再次使用我的普通用户帐户pentest_jake,并使用用户名和密码登录,如图:
然后我提交了我的安全码并拦截请求,用管理员帐户UserId替换了我的hidUserId值,如图:
这样,我就以admin用户登成功录到应用了,如图:
最后,我重申一下,我绝对支持MFA,但实现起来可能会出现问题,而且这些问题非常常见。