Joomla未授权创建用户漏洞分析与防御(CVE-2016-8869)

实验环境

操作机:Windows XP
目标机:Windows 2003
目标地址www.test.ichunqiu

实验工具

Burp Suite:是用于攻击web应用程序的集成平台。它包含了许多工具,并为这些工具设计了许多接口,以促进加快攻击应用程序的过程。所有的工具都共享一个能处理并显示HTTP消息,持久性,认证,代理,日志,警报的一个强大的可扩展的框架,本次试验主要用到它的抓包改包功能

Notepad++:它也是一款编辑器,并且支持代码高亮、代码查询、插件等功能,一般用于代码编辑

实验目的

  1. 了解Joomla未授权创建用户漏洞的形成原理
  2. 掌握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.phpuser.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的意思为创建账号,点击它,来到如下画面,可以看到这是一个填写注册信息的界面
Fig.2
Fig.2

现在来到了注册页面,这时候准备抓取我们正常注册的流量包,用来进行下一步绕过。
抓包必须开启浏览器代理,让流量先经过Burp suite,我们修改后,再让包发出去,这样就可以截取都数据包,为最后一步的伪造数据包做准备

小i提示:开启代理。点击右上角菜单栏,选择选项,在左侧最下面选择高级->网络->设置,这时将代理设置为127.0.0.1,端口设置为8080,准备进行抓包。


打开Burp Suite,双击桌面图标everything,搜索burp,双击第二项,之后点击i accept即可打开软件
Fig.4
Fig.4

小i提示:Burp Suite默认抓包参数为127.0.0.1的8080端口,因此无需配置它,只需配置Web代理和Burp Suite的抓包参数相同即可


点击Register提交按钮,这时要确保Burp Suite的抓包开关处于开启状态
Fig.6
Fig.6

点击后,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,这样就关闭了网站的注册功能


由于之前我已登陆过,因此没有输入账号密码便进去了,同学们登录的时候正常输入账号密码即可。
现在已经关闭了注册的功能,当我们在首页刷新时,会看到创建账号的按钮已经消失。
Fig.10
Fig.10

现在我们构造数据包

首先构造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
Fig.12
Fig.12

右键查看源代码,替换token值。
Fig.13
Fig.13

现在我们已经构造完成了数据包,接下来进行验证,点击Go,提交数据包。
Fig.14
Fig.14

可以看到,我们成功的添加了user12账户,突破注册限制,并绕过了检测机制。

步骤3:修复漏洞

本步将修复漏洞,并验证修复结果

漏洞修复
其实漏洞修复也非常简单,只需要删除user.php中的user register方法即可,官方给出的补丁也是这样修复的。或者升级3.6.4版本,官方也是对user register方法进行了删除。


删除user register方法:来到components/com_users/controllers/user.php将其中293行到366行全部注释掉。
Fig.16
Fig.16

现在点击Go,进行模拟提交:
Fig.17
Fig.17

可以看到创建失败,删除后,只有了一种注册方式,再利用本文中介绍的这种方法,就无从谈起了。

分析与总结

代码审计小技巧
在一般的人工代码审计过程中,大都会选择查找危险函数,然后根据危险函数中的变量回溯到传入变量的方式。虽然这种方式效果很好,但是我们也不应放过变量跟踪。如果你拥有一款不错的变量跟踪自动化工具,那就相对较为方便,如果是手工审计的话,建议,在跟踪函数之前,收集所有可控变量的“最终形态”(所谓最终形 态,就是用户通过各种方式传入进程序经过各种处理后,等待调用时的形态)。这样可以帮助我们能够在跟踪危险函数时,更快的确定,函数是否能被利用。
也许起初作者创作两个注册的页面是为了提升网站的易用性,方便大家更加快捷的使用,但却出现了安全问题,因此,我们要居安思危,自己在编写代码时,安全问题一定要放在首位。
思考
根据本次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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,839评论 6 482
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,543评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 153,116评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,371评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,384评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,111评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,416评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,053评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,558评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,007评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,117评论 1 334
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,756评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,324评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,315评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,539评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,578评论 2 355
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,877评论 2 345

推荐阅读更多精彩内容