实验环境
操作机:Windows XP
目标机:Windows 2003
目标地址:www.test.ichunqiu
实验工具
Burp Suite
:是用于攻击web应用程序的集成平台。它包含了许多工具,并为这些工具设计了许多接口,以促进加快攻击应用程序的过程。所有的工具都共享一个能处理并显示HTTP消息,持久性,认证,代理,日志,警报的一个强大的可扩展的框架,本次试验主要用到它的抓包改包功能
Notepad++
:它也是一款编辑器,并且支持代码高亮、代码查询、插件等功能,一般用于代码编辑
实验目的
- 了解Joomla未授权创建用户漏洞的形成原理
- 掌握Joomla未授权创建用户漏洞利用方式及其修复方法
实验内容
Joomla
Joomla是一套全球知名的内容管理系统。
Joomla是使用PHP语言加上MySQL数据库所开发的软件系统,可以在Linux、 Windows、MacOSX等各种不同的平台上执行。目前是由Open Source Matters(见扩展阅读)这个开放源码组织进行开发与支持。
它是网站的一个基础管理平台,几乎适合从个人网站到百货销售类型的各类网站。
Joomla未授权创建用户漏洞样例介绍
在其3.4.4到3.6.3的版本中,存在漏洞,代号为CVE-2016-8870。
利用该漏洞,攻击者可以在网站关闭注册的情况下注册用户,但在此次演示程序中,存在两个注册用户的页面。其中一个在components/com_users/controllers/registration.php
中的public function register()
函数附近。
public function register()
{
// Check for request forgeries.
JSession::checkToken() or jexit(JText::_('JINVALID_TOKEN'));
// If registration is disabled - Redirect to login page.
if (JComponentHelper::getParams('com_users')->get('allowUserRegistration') == 0)
{
$this->setRedirect(JRoute::_('index.php?option=com_users&view=login', false));
return false;
}
$app = JFactory::getApplication();
$model = $this->getModel('Registration', 'UsersModel');
// Get the user data.
$requestData = $this->input->post->get('jform', array(), 'array');
// Validate the posted data.
$form = $model->getForm();
...
}
另一个在components/com_users/controllers/user.php
中的public function register()
函数中。
public function register()
{
JSession::checkToken('post') or jexit(JText::_('JINVALID_TOKEN'));
// Get the application
$app = JFactory::getApplication();
// Get the form data.
$data = $this->input->post->get('user', array(), 'array');
// Get the model and validate the data.
$model = $this->getModel('Registration', 'UsersModel');
$form = $model->getForm();
...
}
这两段代码分开来看,是没有任何问题的,但是,当两者在同一网站程序中,就出现了问题,其中registration.php
中有检测网站是否开启或关闭注册功能的代码,而user.php
中没有相关功能,因此当网站的注册功能关闭后,我们可以通过抓包修改cookie,替换内容,将内容提交到user.php中,从而达到注册账号的目的。
漏洞影响版本
Joomla 3.4.4 => 3.6.3
漏洞危害
Joomla是一套全球知名的内容管理系统,它的影响范围极大,只要版本在3.4.4到3.6.3之间,攻击者可以伪造数据包,在网站关闭注册新用户的情况下,绕过关闭检测,进行未授权注册账号,从而危害网站安全。
实验步骤
步骤1:漏洞代码分析
本步将对漏洞代码进行分析
本次的漏洞起因在于两个注册功能的代码文件上,分别为registration.php
和user.php
,一般情况下,一个网站有一个注册的功能即可,但本次joomla出现了两个有注册功能的代码,也许设计者有别的考虑,但在两个注册模块中,user.php
没有检测网站是否关闭注册的代码,通过提交参数,抓包修改cookie,就可以突破关闭注册的限制。
访问tools.ichunqiu.com/lh4jtfcc
下载网站源码,点击右键,解压到本地,打开目录components/com_users/controllers/
找到registration.php点击右键使用Notepad++打开,并使用搜索功能ctrl+F,输入function register
进行搜索。
首先分析registration.php
中部分关键源码:
public function register()
{
// Check for request forgeries.
JSession::checkToken() or jexit(JText::_('JINVALID_TOKEN'));
// If registration is disabled - Redirect to login page.
if (JComponentHelper::getParams('com_users')->get('allowUserRegistration') == 0)
{
$this->setRedirect(JRoute::_('index.php?option=com_users&view=login', false));
return false;
}
$app = JFactory::getApplication();
$model = $this->getModel('Registration', 'UsersModel');
// Get the user data.
$requestData = $this->input->post->get('jform', array(), 'array');
// Validate the posted data.
$form = $model->getForm();
...
}
通过阅读上述代码得知,第一段代码的作用是检测了,第二段的代码意思是:检查网站的注册功能是否关闭,如果关闭,则跳到网站登录页面,最后一段则是:获取用户的输入的数据,最后进行数据验证,注意这里是使用post来请求来获取jform的。
接下来查看user.php
中的内容,打开目录components/com_users/controllers/
,找到user.php点击右键使用Notepad++打开:
public function register()
{
JSession::checkToken('post') or jexit(JText::_('JINVALID_TOKEN'));
// Get the application
$app = JFactory::getApplication();
// Get the form data.
$data = $this->input->post->get('user', array(), 'array');
// Get the model and validate the data.
$model = $this->getModel('Registration', 'UsersModel');
$form = $model->getForm();
...
}
这里的内容与registration.php
中大致相同,但有两处值的我们注意的地方。
1:user.php中没有检查是否关闭注册的相关功能。
2:获取数据的时候是获取user参数,而registration.php则是获取jform参数。
既然user.php没有检查是否关闭注册,我们可以尝试使用抓包改包的方法,让user去处理我们提交的数据,这样或许可以绕过检测。
步骤2:验证漏洞
本步将对漏洞进行验证。
本步大致流程:
在注册开关打开的情况下,注册一个账号,通过Burp Suite抓取数据包,然后将注册功能关闭,通过修改数据包,突破检测限制。
首先打开目标网站http://www.test.ichunqiu
,注册账号:
我们打开目标网站,来到首页,看到登录界面,首先先创建一个账号:
其中
Create an account
的意思为创建账号,点击它,来到如下画面,可以看到这是一个填写注册信息的界面现在来到了注册页面,这时候准备抓取我们正常注册的流量包,用来进行下一步绕过。
抓包必须开启浏览器代理,让流量先经过Burp suite,我们修改后,再让包发出去,这样就可以截取都数据包,为最后一步的伪造数据包做准备
小i提示:开启代理。点击右上角菜单栏,选择选项,在左侧最下面选择高级->网络->设置,这时将代理设置为127.0.0.1,端口设置为8080,准备进行抓包。
打开Burp Suite,双击桌面图标everything,搜索
burp
,双击第二项,之后点击i accept即可打开软件小i提示:Burp Suite默认抓包参数为127.0.0.1的8080端口,因此无需配置它,只需配置Web代理和Burp Suite的抓包参数相同即可
点击Register提交按钮,这时要确保Burp Suite的抓包开关处于开启状态
点击后,Burp Suite会抓到注册信息的包,如下:
POST /index.php/component/users/?task=registration.register HTTP/1.1
Host: 192.168.65.240
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:49.0) Gecko/20100101 Firefox/49.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
Referer: http://192.168.65.240/index.php/component/users/?view=registration
Cookie: 1982548f16255720da32edd9a5a2460a=e5bla03hh9bhnk3ltd3n4u1tg1; 9a923bca761a60bf05e500c931023857=0jg34edl0mohol3f6gbng0cue3
Connection: close
Upgrade-Insecure-Requests: 1
Content-Type: multipart/form-data; boundary=---------------------------8451993725873
Content-Length: 1048-----------------------------8451993725873
Content-Disposition: form-data; name="jform[name]"user1-----------------------------8451993725873
Content-Disposition: form-data; name="jform[username]"user1-----------------------------8451993725873
Content-Disposition: form-data; name="jform[password1]"user1-----------------------------8451993725873
Content-Disposition: form-data; name="jform[password2]"user1-----------------------------8451993725873
Content-Disposition: form-data; name="jform[email1]"user1@qq.com-----------------------------8451993725873
Content-Disposition: form-data; name="jform[email2]"user1@qq.com-----------------------------8451993725873
Content-Disposition: form-data; name="option"com_users-----------------------------8451993725873
Content-Disposition: form-data; name="task"registration.register-----------------------------8451993725873
Content-Disposition: form-data; name="2af7830a5505f03670ae29878a741652"
我们点击右键,发送到repeater,点击Go,进行模拟提交:
小i提示:有时我们构造的语句不一定能成功执行,这时就可以用到repeater功能,它非常方便,只需获取到数据包,点击一次Go,就可以向目标发送一次之前数据包的内容,我们理论上可以无限制的发送数据包,直到我们获取到想要达到的效果
提交后,查看user1用户是否成功添加,只需在首页登陆即可:
可以看到,成功的登录,接下来我们要将注册的功能关闭,利用修改刚才抓取的数据包,进行绕过注册限制。
本步将在注册功能关闭的情况下,通过修改数据包,突破限制
现在登录管理员账号,将注册功能关掉,管理员的后台在administrator
目录下:
我们在网站后面输入administrator,进入登陆界面,填入管理员账号密码(skmter、skmter),再点击system
菜单下的Global Configuration
,选择最后一项user
,将User Options
选项下的Allow user registration
设置为NO,这样就关闭了网站的注册功能
由于之前我已登陆过,因此没有输入账号密码便进去了,同学们登录的时候正常输入账号密码即可。
现在已经关闭了注册的功能,当我们在首页刷新时,会看到创建账号的按钮已经消失。
现在我们构造数据包
首先构造Cookie,将它换成正常登录时的Cookie,因为此时网站注册功能已经关闭,必须伪装成正常的提交页面才可以正常提交。
那么如何获取Cookie呢?
我们只需先开启Burp Suite的抓包开关,在首页按F5或者刷新按钮,刷新一次,这样Burp Suite就可以截获到Cookie,截取后我们复制它,覆盖之前数据包中的Cookie即可,如图
在步骤1结尾处我们已经了解,要想使用user.php来处理我们提交的数据,就需要用到user来替换jfrom,这样就可以通过user传值。在数据包的最后一项,我们可以看到,表单的name是user,并在user.php中用post获取user,在网站首页右键查看源代码,可以获取到user的name的token值。直接替换即可:
将jfrom替换为user
右键查看源代码,替换token值。
现在我们已经构造完成了数据包,接下来进行验证,点击Go,提交数据包。
可以看到,我们成功的添加了user12账户,突破注册限制,并绕过了检测机制。
步骤3:修复漏洞
本步将修复漏洞,并验证修复结果
漏洞修复
其实漏洞修复也非常简单,只需要删除user.php
中的user register方法即可,官方给出的补丁也是这样修复的。或者升级3.6.4版本,官方也是对user register方法进行了删除。
删除user register方法:来到
components/com_users/controllers/user.php
将其中293行到366行全部注释掉。现在点击Go,进行模拟提交:
可以看到创建失败,删除后,只有了一种注册方式,再利用本文中介绍的这种方法,就无从谈起了。
分析与总结
代码审计小技巧
在一般的人工代码审计过程中,大都会选择查找危险函数,然后根据危险函数中的变量回溯到传入变量的方式。虽然这种方式效果很好,但是我们也不应放过变量跟踪。如果你拥有一款不错的变量跟踪自动化工具,那就相对较为方便,如果是手工审计的话,建议,在跟踪函数之前,收集所有可控变量的“最终形态”(所谓最终形 态,就是用户通过各种方式传入进程序经过各种处理后,等待调用时的形态)。这样可以帮助我们能够在跟踪危险函数时,更快的确定,函数是否能被利用。
也许起初作者创作两个注册的页面是为了提升网站的易用性,方便大家更加快捷的使用,但却出现了安全问题,因此,我们要居安思危,自己在编写代码时,安全问题一定要放在首位。
思考
根据本次Joomla漏洞演示,请思考,在Joomla的注册页面,你认为还应添加哪些安全方面的检测功能?
参考资料
http://blog.knownsec.com/2016/10/joomla-register-users-cve-2016-8870/
https://www.youtube.com/watch?v=Q_2M2oJp5l4
课后习题
第1题:如何获取inde.php的cookie值?
A、通过访问index.php右键查看源代码获取
B、通过火狐浏览器cookie查看器,输入命令cookie来获取
C、通过抓包获取
第2题:可以通过通过访问index.php右键查看源代码获取index.php的token值?
A、对
B、不对
第3题:实验中除过管理员账户和同学们自己创建用户外,还有另外一个用户,它的用户名为_______ 。
参考答案:
1、C;2、A;3、ichunqiu123