我是如何黑掉会议系统的?
导语:OpenCFP是一个开源的会议讨论系统,是用PHP写的。很多的会议都用这套系统,包括Immunity的渗透会议以及其他很多会议。
OpenCFP是一个开源的会议讨论系统,是用PHP写的。很多的会议都用这套系统,包括Immunity的渗透会议以及其他很多会议。在一次对OpenCFP的代码审计中,我找到了一个bug,本篇文章就是对这个bug的一个报告。
这个漏洞是OpenCFP使用的第三方身份认证框架Sentry造成的,该框架是由 Cartalyst开发的。尽管在新版本的OpenCFP中已经不用Sentry框架了,但是在实际环境中依然有许多OpenCFP系统中存在这个问题。
和大部分app一样,OpenCFP也提供了一个“忘记密码”功能可以让用户通过邮箱来设置新密码。如以下页面:
点击“change mypassword”按钮的时候,会向服务器发送一个POST请求包,如下图:
发送成功后,服务端会匹配参数reset[reset_code]的值和该用户在数据库中 reset_password_code字段的值。这个过程OpenCFP是通过Sentry框架完成这个身份认证。
问题出现在Sentry框架如何执行这个认证的过程中。事实上,根据Sentry框架的数据库结构,如果用户没有重置密码的话,数据库中reset_password_code字段默认存储的是NULL:
除了一些基本的输入处理,Sentry框架并没有进一步验证输入是否由OpenCFP发送。而且,Sentry并没有在输入过滤方面提供相关建议。
下图是Sentry框架中用来验证的函数,主要用来验证请求包中的reset code是否和数据库中的相同。函数的返回很简单,就是true(匹配上了)和false(没匹配到)。
该检查函数在attemptResetPassword()函数中被调用。注意,用户的reset code会被修改回NULL,和新密码一起更新到数据库中:
这个bug本身非常简单。问题在于,如果NULL这个值可以传入checkResetPasswordCode()函数的话。那么该函数拿着NULL去数据库中匹配,那么,所有没有要修改密码的用户返回出的结果一定是True的。然后,我们用NULL的符号(%00)在请求包中构造这样的输入,把reset[reset_code] 的值设置成如下:
返回的结果自然是验证成功了。
这个漏洞可以用来重置任何OpenCFP用户的密码,只要他们的数据库中没有重设密码的令牌。不过攻击者要想登录的话,还是需要将用户ID和email关联起来才行,不过这也不是什么难题,因为通常1-5号用户就是主管。
最后,必须提醒下,其他用了Sentry框架的应用也可能存在同样的问题,尤其是,现在基本上每个网站都会有“忘记密码”这个功能。如果你身边的朋友使用的是Sentry框架,记得提醒他们升级系统。
发表评论