RSS Feed
更好更安全的互联网
  • Nginx权限提升漏洞(CVE-2016-1247) 分析

    2016-11-23

    Author:xd0ol1(知道创宇404实验室) data:2016-11-17

    0x00 漏洞概述


    1.漏洞简介

    11月15日,国外安全研究员 Dawid Golunski 公开了一个新的Nginx漏洞(CVE-2016-1247),能够影响基于 Debian 系列的发行版,Nginx 作为目前主流的一个多用途服务器,因而其危害还是比较严重的,官方对此漏洞已经进行了修复。

    2.漏洞影响

    Nginx服务在创建log目录时使用了不安全的权限设置,可造成本地权限提升,恶意攻击者能够借此实现从 nginx/web 的用户权限 www-data 到 root 用户权限的提升。

    3.影响版本

    下述版本之前均存在此漏洞:
    Debian: Nginx1.6.2-5+deb8u3
    Ubuntu 16.04: Nginx1.10.0-0ubuntu0.16.04.3
    Ubuntu 14.04: Nginx1.4.6-1ubuntu3.6
    Ubuntu 16.10: Nginx1.10.1-0ubuntu1.1

    0x01 漏洞复现


    1.环境搭建

    测试环境:Ubuntu 14.04: Nginx1.4.6-1ubuntu3

    PoC详见如下链接,给出的 nginxed-root.sh 脚本在其中的第V部分:
    https://legalhackers.com/advisories/Nginx-Exploit-Deb-Root-PrivEsc-CVE-2016-1247.html

    2.漏洞触发

    恶意者可通过软链接任意文件来替换日志文件,从而实现提权以获取服务器的 root 权限,执行 PoC 后结果如下图:

    5

    提示要等待,但我们可以通过如下命令进行触发:

    提权后的结果如下:

    6

    3.漏洞利用分析

    一般来说,如果想要修改函数的功能,最直接的就是对其源码进行更改,但很多情况下我们是无法达成此目标的,这时就可以借助一些hook操作来改变程序的流程,从而实现对函数的修改。在 Linux 系统下,我们可以通过编译一个含相同函数定义的 so 文件并借助/etc/ld.so.preload文件来完成此操作,系统的 loader 代码中会检查是否存在/etc/ld.so.preload 文件,如果存在那么就会加载其中列出的所有 so 文件,它能够实现与 LD_PRELOAD 环境变量相同的功能且限制更少,以此来调用我们定义的函数而非原函数。此方法适用于用户空间的so文件劫持,类似于 Windows 下的 DLL 劫持技术。更进一步,如果我们将此技巧与含有suid的文件结合起来,那么就可以很自然的实现提权操作了,所给的 PoC 就是利用的这个技巧。

    关于 hook 操作,简单来看就是如下的一个执行流程:

    7

    在 PoC 利用中与此相关的 C 代码如下所示,如果将其编译成so文件并把路径写入到/etc/ld.so.preload文件的话,那么可以实现对 geteuid()函数的 hook,在 hook 调用中就能执行我们想要的恶意操作。

    我们可以将上述代码编译后来做个简单的测试,结果如下图,观察 nginxrootsh 文件前后属性的变化以及/etc/ld.so.preload文件存在与否可以判断我们的恶意操作是否执行了,很显然 hook 是成功的,和 PoC 相同这里也是通过sudo来触发hook调用。

    8

    接下来我们考虑下如何将内容写进/etc/ld.so.preload文件,也就是本次漏洞的所在,Nginx 在配置 log 文件时采用的不安全权限设置使得我们能很容易的实现此目的,从而实现 www-data 到 root 的权限提升。为了看的更清楚,我们首先将目录/var/log/nginx/下的文件全部删除,再重启下 nginx 服务,最后执行如下两条命令:

    此时得到的结果如下图所示:

    9

    可以看到 error.log 文件的属性为:

    将其软链接到/etc/ld.so.preload 文件就可以了,这里为了简单测试,我们将其软链接到/etc/xxxxxxxxxx,同样需要上述那两条触发命令。从上图中我们看到了成功结果,此时 www-data 用户是可以对/etc/xxxxxxxxxx文件进行写操作的。

    至此,我们将这些点结合起来就可以实现对此漏洞的利用了。

    0x02 修复方案


    Nginx官方已经修复,用户应尽快更新至最新版本。

    详细信息:

    Debian 系统

    https://www.debian.org/security/2016/dsa-3701

    https://security-tracker.debian.org/tracker/CVE-2016-1247

    Ubuntu 系统

    https://www.ubuntu.com/usn/usn-3114-1/

    0x03 参考


    https://www.seebug.org/vuldb/ssvid-92538
    https://legalhackers.com/advisories/Nginx-Exploit-Deb-Root-PrivEsc-CVE-2016-1247.html
    https://minipli.wordpress.com/2009/07/17/ld_preload-vs-etcld-so-preload/
    http://fluxius.handgrep.se/2011/10/31/the-magic-of-ld_preload-for-userland-rootkits/

    作者:kk | Categories:安全研究 | Tags:
  • Sparkjava Framework 文件遍历漏洞(CVE-2016-9177)分析与探究

    2016-11-17

    Author:dawu(知道创宇404实验室) data:2016-11-16

    0x00 漏洞概述


    1.漏洞简介

    Sparkjava是一款小型的web框架,它能够让你以很少的代码构建出一个java web应用。近日,某国外安全研究人员发现其存在文件遍历漏洞,可以通过该漏洞读取任意文件内容。在对这个漏洞进行复现与分析的时候,我们又发现了一些可能可以利用的地方,但是利用条件更加苛刻。

    2.漏洞影响

    Sparkjava版本 < 2.5.2

    0x01 漏洞复现

    1.验证环境

    Jdk-1.8.111 Apache maven 3.3.9 在写好Sparkjava代码后,在文件所在目录打开命令行,运行mvn package进行编译打包。

    2.漏洞复现

    根据官网给出的示例,我们写了一个简单的函数去复现这个漏洞:

    pom.xml的配置为xml <dependency> <groupId>com.sparkjava</groupId> <artifactId>spark-core</artifactId> <version>2.5</version> </dependency>这里提供已经打包好的jar文件供大家下载。可以用如下命令运行:bash java -jar sparkexample-jar-with-dependencies.jar 我们可以通过(..\)来改变路径从而读取任意文件。如图,我们读取到/etc/passwd:

    复现

    在漏洞发现者的描述中,Spark.staticFileLocation()和Spark.externalStaticFileLocation()这两个函数都存在这个问题。经过开发者测试,在IDE中运行时,两个函数都可以复现这个漏洞;运行打包好的jar包时,只有Spark.externalStaticFileLocation()这个函数可以触发漏洞。

    0x02 补丁分析与深入研究


    1.补丁分析

    很明显,在漏洞被发现时,官方没有对url中的路径做任何处理。在漏洞被修补之后,官方推出了新的版本2.5.2。这里我们对比之前的版本,并且通过调试,尝试分析官方的修补方案。 官方修补链接(https://github.com/perwendel/spark/commit/efcb46c710e3f56805b9257a63d1306882f4faf9) 当我们正常请求时:bash curl "127.0.0.1:4567/l.txt" 跟到关键代码处,我们可以看到在判断文件是否存在之后,官方添加了DirectoryTraversal.protectAgainstInClassPath(resource.getPath());进行判断。

    动态调试1

    这里,path就是我们HTTP请求的地址,addedPath就是我们通过staticFiles.externalLocation()函数设置的路径与path拼接之后的值,resource中的file的值就是addedPath值经过路径的处理的值(例如:/tmp/test/..\l.txt先将所有的\换成/,再对路径进行处理,最后结果为/tmp/l.txt),resource.getPath()就是addedPath的值。

    动态调试2

    protectAgainstInClassPath()函数中,需要判断removeLeadingAndTrailingSlashesFrom(path).startsWith(StaticFilesFolder.external())是否为false,为false就抛出。

    removeLeadingAndTrailingSlashesFrom(path)为新添加的函数,作用是将path首尾的/去掉和将尾部的\去掉。在这里经过处理之后,path的值为tmp/l.txt

    StaticFilesFolder.external()则是返回external的值,在这里就是tmp。如果removeLeadingAndTrailingSlashesFrom(path)前面的字母是tmp,则进入下一步。

    综上所述,官方通过比较经过处理后的路径的开头和我们设置的externalLocation()的路径是否相同来防止我们利用..\读取任意文件。

    2.深入探究

    我们修改了pom.xml,使用新的Sparkjava版本进行编译尝试,做了如下探究。xml <dependency> <groupId>com.sparkjava</groupId> <artifactId>spark-core</artifactId> <version>2.5.2</version> </dependency>

    ①软链接的利用

    与Sparkjava(CVE-2016-9177)同时爆出来的一个漏洞GitLab的任意文件读取(CVE-2016-9086)是利用软链接的特性,我们就顺手测试了软链接在Sparkjava下的利用。 直接读取文件:file

    path

    怎么才能利用软链接呢?这里的利用条件比较苛刻。笔者想到了两种途径: 1.网站允许上传压缩包,上传后解压并且还能访问到解压后的文件才能利用 2.网站通过wget(wget配置文件中需要retr-symlinks=on)从ftp上下载文件并且能够访问到下载的文件。

    ②再次读取文件

    我们在根目录下新建两个文件tmp.txt,tmp2.txttmp

    再访问

    tmp2

    读取到了tmp.txt和tmp2.txt的内容。 我们分析一下能够再次读取的原因,当我们请求为: bash curl “127.0.0.1:4567/tmp\..\..\tmp.txt” 分析过滤代码处: read1

    addedPath的值为/tmp/tmp/..\..\tmp.txt,经过处理后resource中的file值为/tmp.txt,对于下面的函数removeLeadingAndTrailingSlashesFrom(path).startsWith(StaticFilesFolder.external()),由于tmp.txt也是由tmp开头,所以判断可以通过,进而读取到tmp.txt

    同样的道理,我们也可以读取到/tmp2/test.txt的内容。

    tmp3

    通过以上分析,笔者认为这个读取很鸡肋,首先staticFiles.externalLocation()中定义的路径只能是一级路径,其次我们要读取的文件的完整路径开头必须和staticFiles.externalLocation()中定义的路径相同。这就限制了这个新的读取,也许只有在某些特定的场合才能有奇效。

    如有错误,欢迎指正:)

    0x03 参考链接


    1.https://www.seebug.org/vuldb/ssvid-92517 2.http://seclists.org/fulldisclosure/2016/Nov/133.https://github.com/perwendel/spark/commit/efcb46c710e3f56805b9257a63d1306882f4faf94.https://github.com/perwendel/spark/issues/700 5.http://sparkjava.com/documentation.html

     

    作者:kk | Categories:安全研究技术分享 | Tags:
  • GitLab 任意文件读取漏洞 (CVE-2016-9086) 和任意用户 token 泄露漏洞 分析

    2016-11-10

    Author:dawu,LG(知道创宇404安全实验室) Data:2016-10-09

    0x00 漏洞概述


    1.漏洞简介

    GitLab 是一个利用Ruby on Rails开发的开源应用程序,实现一个自托管的Git项目仓库,可通过Web界面进行访问公开的或者私人项目。近日研究者发现在其多个版本中存在文件读取漏洞(CVE-2016-9086)任意用户authentication_token泄漏漏洞,攻击者可以通过这两个漏洞来获取管理员的权限,进而控制所有gitlab项目。

    2.漏洞影响

    • 任意文件读取漏洞(CVE-2016-9086):
      GitLab CE/EEversions 8.9, 8.10, 8.11, 8.12, and 8.13
    • 任意用户authentication_token泄露漏洞:
      Gitlab CE/EE versions 8.10.3-8.10.5

    0x01 漏洞复现


    1.环境搭建

    这里使用8.10.3版本是为了任意用户authentication_token泄露漏洞的复现。

    安装完成后,访问服务器80端口即可看到GitLab登录页面。

    注:8.9.0-8.13.0版本的GitLab的项目导入功能需要管理员开启,8.13.0版本之后所有用户都可以使用导入功能。管理员可以访问http://domain/admin/application_settings 开启,开启之后用任意用户新建项目的时候,可以在import project from一项中看到gitlab export。

    2.漏洞分析

    任意文件读取漏洞(CVE-2016-9086)

    8.9.0版本开始,GitLab新增了导入导出项目的功能。
    一个空的gitlab项目导出后结构如下:

    export

    其中VERSION文件内容为GitLab的导出模块的版本,project.json则包含了项目的配置文件。

    当我们导入GitLab的导出文件的时候,GitLab会按照如下步骤处理: 1.服务器根据VERSION文件内容检测导出文件版本,如果版本符合,则导入。
    2.服务器根据Project.json文件创建一个新的项目,并将对应的项目文件拷贝到服务器上对应的位置。

    检测VERSION文件的代码位于:/lib/gitlab/import_export/version_checker.rb中:

    我们可以看到这里的逻辑是读取VERSION文件的第一行赋值给变量version,然后检测verison与当前版本是否相同,相同返回true,不相同则返回错误信息(错误信息中包括变量version的值). 于是漏洞发现者Jobert Abma巧妙的使用了软链接来达到读取任意文件的目的。首先,我们给VERSION文件加上软链接并重新打包。

    version_link

    这样,读取VERSION文件的时候服务器就会根据软链接读取到/etc/passwd的第一行内容并赋值给version。但是由于version与当前版本不相同,所以会输出version的值,也就是/etc/passwd第一行的内容。

    访问之前搭建好的GitLab服务器,创建一个新的项目,填写完项目名称后在Import project from一栏中选择GitLab export,上传我们修改后的导入包,然后就可以看到/etc/passwd文件第一行

    VERSION

    但是,如果只读取任意文件的第一行,能做的事情还是太少了。漏洞发现者显然不满足这一结果,他继续找了下去.
    读取Project.json这一配置文件的代码位于:/lib/gitlab/import_export/project_tree_restorer.rb中:

    在这里,我们可以再次使用软链接使变量json获取到任意文件的内容,但是由于获取的文件不是json格式,无法decode,导致异常抛出,最终在前端显示出任意文件的内容。 添加软链接并打包:

    json_link

    上传导出包,页面上显示的结果:

    json

    任意用户authentication_token泄露漏洞

    复现步骤为:

    1.注册一个普通用户,创建一个新的项目
    2.在项目的member选项中,添加管理员到项目中。

    add_admin

    3.点击edit project,找到Export project部分,点击Export project,等待几分钟去查看注册邮箱收到的下载地址或者刷新页面,点击Download export下载导出包。

    download

    4.导出包的project.json中已经含有了管理员的authentication_token

    admin_token

    得到authentication_token之后我们就可以通过api做管理员可以做的事情了,比如查看管理员所在的项目:

    get_all_project

    分析原因:

    我们在\app\controllers\projects_controller.rb中找到了export函数,这个函数被用来导出项目文件。

    往下跟add_export_job(),在\app\models\project.rb中:

    继续到\app\workers\project_export_worker.rb文件的ProjectExportWorker.perform_async():

    这里我们可以看到current获取的是User.find(current_user_id)的内容,然后调用::Projects::ImportExport::ExportService.new(project, current_user).execute 由于笔者之前没有接触过ruby,这里只好采用gitlab-rails console来找到User.find()的值。可以看到,在User.find()中,存在authentication_token的值。

    User.find

    跟到\app\services\project\import_export\export_service.rb,这里执行version_saver, avatar_saver, project_tree_saver, uploads_saver, repo_saver, wiki_repo_saver这五个函数来写各种导出文件,其中project_tree_saver()负责导出project.json

    跳过之后的几个繁琐的调用之后,执行了lib/gitlab/import_export/json_hash_builder.rb中的create_model_value函数。

    这里出现了逻辑问题,由于parsed_hash这个变量不是全局变量,所以create_model_value()中执行parse_hash()时,parse_hash()中的parsed_hash被改变,但是create_model_value()函数中的parsed_hash不会变,这就造成了parse_hash()这个函数执行后create_model_value()parsed_hash这个值并没有改变。因此最后导出的文件包含了authentication_token

    我们在gitlab-rails console里展示了这两者的区别。当value=user的时候,parsed_hash={:include=>:user},输出的结果如同图中的user.as_json(),会将所有内容输出,包括authentication_token。当parsed_hash为经过parse_hash()处理后的{:include=>{:user=>{:only=>[:id, :email, :username]}}}时,输出结果与user.as_json(only: [:id, :email, :username])相同。

    include_only

    后续RCE方式的探讨

    hackone的两个报告中,漏洞发现者都提到了leads to RCE,笔者尝试去实现这一点。由于GitLab源码在gitlab.com上,所以当获取了GitLab的管理员权限后,我们可以通过authentication_token修改GitLab项目的源码,留下自己的后门。 为了重现这种情况,我们在本地新建一个新的项目去通过authentication_tokenGitLab api来修改项目文件。

    root账户创建一个项目:test_rce,其中README.md的内容为created by root

    admin_test

    接下来,我们要用gitlabapi来修改它。首先,根据projects的api找到test_rce项目对应的id,这里是18

    find_project_id

    我们再根据api读取一下文件

    read_file

    这里,contentY3JlYXRlZCBieSByb290,这是文件内容被base64加密后的结果,解密一下就可以看到created by root

    base64decode1

    根据api的要求,我们通过PUT数据来修改文件,将README.md修改为change by notroot。 当我们再读一次,content内容为:Y2hhbmdlIGJ5IG5vdHJvb3Q=,解码之后就是change by notroot

    changefile

    base64decode2

    不得不说,笔者所实现的这种方式攻击时间跨度很长,能否执行命令取决于开发者下一次更新的时间,这也是这种方法的缺点之一。

    0x02 官方修复分析


    任意文件读取漏洞(CVE-2016-9086)修复分析

    symbolic_link_repair

    我们可以看到,官方先移除了导入包里的软连接,其次,读取VERSION的内容和project.json的内容出错后将内容输出到日志里而非返回到前端。

    任意用户authentication_token泄露漏洞修复分析

    token_repair

    官方让json_config_hash[current_key]获取到parse_hash()处理后的值。

    0x03 参考

     


    作者:kk | Categories:安全研究技术分享 | Tags:
  • GNU tar 解压路径绕过漏洞(CVE-2016-6321) 分析

    2016-11-10

    Author: LG(知道创宇404安全实验室) Date: 2016-11-09

    0x00 漏洞概述


    1.漏洞简介

    GNU tar文档管理命令是Linux系统下常用的一个打包、压缩的命令。经 CSS(FSC1V Cyber Security Services)团队的研究员 Harry Sintonen 研究发现,tar 命令在提取路径时能够被绕过,在某些情况下导致文件被覆盖。在一些特定的场景下,利用此漏洞可导致远程代码执行。

    2.漏洞影响

    受害者使用tar命令解压由攻击者构造的特殊 tar 包时,tar 包不会解压到受害者制定的目标路径,而是被解压到攻击者指定的目录位置。

    3.影响范围

    从GNU tar 1.14 to 1.29 (包含1.29) 影响包括 Red Hat,Alphine Linux,Red Star OS以及其他所有使用 GNU tar 的 Linux 系统。

    0x01 漏洞详情


    1. 漏洞检测

    方法一:

    漏洞发现者给出了示例 PoC,用户可用其自检。 (该方法会覆盖用户帐号密码,导致 root 用户密码为空,建议使用实验环境测试或者采用方法二)

    示例poc:

    example_poc

    示例poc中含有一个文件shadow,路径为etc/motd/../etc/shadow。在根目录下解压该包,由于漏洞的影响,../前面的内容给去掉了,路径文件名只剩下etc/shadow,原有etc/shadow文件就被其覆盖了。

     

    方法二:

    访问https://sintonen.fi/advisories/tar-poc.tar下载测试tar包后在提取前重命名 tar 包内的 shadow 文件名,如重命名为 test。然后运行如下命令:

    查看 etc 目录下,若生成了 test 文件,证明该漏洞存在。

    2.具体攻击场景

    以下为漏洞发现者提供的实际攻击场景

    1.攻击者可以用这种手段诱使用户替换一些重要的文件,例如 .ssh/authorized_keys.bashrc , .bash_logout , .profile, .subversion.anyconnect

    2.有一些从 web 应用或者其它类似来源自动解压文件的脚本,这些脚本一般会以 setuid root 权限执行,通常这类脚本的解压命令如下:

    在这种情况下,攻击者可以重写/var/spoon/cron/crontabs/root以获取 root 身份的代码执行能力; 也可以将可能被 root 身份执行的二进制文件替换成一个有后门的版本; 或者投放一个 setuid root 的二进制文件,等待被管理员执行,使攻击者有机会获取 root 权限。

    3.以 root 身份执行解压命令也可能被攻击 。例如上文中提到覆写/etc/shadow的例子

    tar1

    如果--exclude 规则与--anchored 选项同时使用,那么即使手动加了--exclude 规则也没有用,例如:

    tar2

    在两种情况下,攻击者都成功地把/etc/test替换成了任意内容。

    不过,在实际利用这个漏洞时,攻击者需要首先知道一些特定的前导信息,例如解压命令执行时实际在命令行下指定的路径名,毕竟在构造攻击 tar 包时 “../” 序列之前的路径前缀需要符合 tar 命令中所输入的路径,攻击才能奏效。

    3.漏洞分析

    根据漏洞发现者的分析,在lib/paxnames.c文件中,有一个safernamesuffix()函数,这个函数取代了1.13版本的检查机制。

    从代码注释可以看出,如果absolute_names变量为1,将 filename 赋值给 p 继续.反之若为 0 则将文件名中文件系统的前缀给去掉,并且也会对 filename 进行一些安全检查 。 因此,当 tar 解包时若文件名中包含“../”, safernamesuffix 函数会删除"../"及其之前的部分,将其与解压目录路径变为相对关系。这么做的目的是在兼顾文件名的安全性时保证文件的提取,而不是之前版本中改动的跳过含有恶意文件名的文件。在经过长达13年的应用后,这个漏洞终于被 Harry Sintonen 发现并公布出来。

    于是,笔者研究了这个漏洞相关的发展历史。 tar所有版本下载链接 发现:

    • tar通过 src/extarct.c 提取文件
    • extract.c Revision 1.35 前未加入安全检测,可以通过“../”字符串直接绕过解压路径问题,并将文件写到任意位置
    • extract.c Revision 1.35 加入安全检测,会警告压缩文件文件名中存在“..”字符串,并且会跳过不去处理这些文件
    • extract.c Revision 1.47引入 safernamesuffix 函数 - tar 1.16版本后,extract.c文件代码重构,在lib/paxnames.c 文件中定义 safernamesuffix 函数

    然后笔者继续深入,通过tar官网extract.c文件更新列表对比,从源代码分析 tar 的安全检测行为。

    1999/12/13 commit 前后对比

    Revision 1.35官方tag中有一条: ++(extractarchive): By default, warn about ".." in member names, and skip them.++ 即Revision 1.35加入了(extractarchive):默认情况下,在成员名称中警告“..”,并跳过它们 初版修复

    上图中,绿色代码区的功能就填补了之前安全检测的空白。它首先遍历 CURRENTFILENAME,如果存在".."就会警告"Member name contains'..'",然后跳过这些文件,不去处理它们。而左边的灰色空白区域表明之前的版本缺少安全检测,"../"字符串就能绕过解压路径将文件写到任意位置。

    2003/07/05 commit 前后对比

    在Revision 1.47官方 tag 中: ++(extractarchive): Use safername_suffix rather than rolling our own.++ 这就是漏洞初始出现的位置了。

    漏洞之处

    通过代码对比我们可以看到,更新的版本使用 safernamesuffix 函数来替代了开发者自己写的规则。

    4.补丁分析

    官方补丁地址 GNU tar修复了该漏洞,将安全检测机制重新替换回了 extract.c Revision 1.35的规则。

    补丁

    0x02 修复方案


    更新补丁

    http://git.savannah.gnu.org/cgit/tar.git/commit/?id=7340f67b9860ea0531c1450e5aa261c50f67165d

    0x03 参考


    https://www.seebug.org/vuldb/ssvid-92524

    https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=842339

    https://sintonen.fi/advisories/tar-extract-pathname-bypass.proper.txt

    https://sintonen.fi/advisories/tar-extract-pathname-bypass.patch

    https://www.gnu.org/software/tar/

    http://cvs.savannah.gnu.org/viewvc/tar/tar/src/extract.c?view=log&pathrev=release115_1#rev1.47

    作者:kk | Categories:安全研究技术分享 | Tags:
  • Joomla未授权创建特权用户漏洞(CVE-2016-8869)分析

    2016-10-28

    Author: p0wd3r (知道创宇404安全实验室) Date: 2016-10-26

    0x00 漏洞概述


    1.漏洞简介

    Joomla是一个自由开源的内容管理系统,近日研究者发现在其3.4.4到3.6.3的版本中存在两个漏洞:CVE-2016-8869CVE-2016-8870。我们在这里仅分析 CVE-2016-8869,利用该漏洞,攻击者可以在网站关闭注册的情况下注册特权用户。Joomla 官方已对此漏洞发布升级公告

    2.漏洞影响

    网站关闭注册的情况下仍可创建特权用户,默认状态下用户需要用邮件激活,但需要开启注册功能才能激活。

    3.影响版本

    3.4.4 to 3.6.3

    0x01 漏洞复现


    1. 环境搭建

    解压后放到服务器目录下,例如/var/www/html

    创建个数据库:

    2.漏洞分析

    注册

    注册部分可参考:《Joomla未授权创建用户漏洞(CVE-2016-8870)分析》

    提权

    下面我们来试着创建一个特权用户。

    在用于注册的register函数中,我们先看一下$model->register($data)这个存储注册信息的方法,在components/com_users/models/registration.php中:

    可以看到这里使用我们可控的$temp$data赋值,进而存储注册信息。正常情况下,$data在赋值之前是这样的:

    data-common

    而正常情况下我们可控的$temp中是没有groups这个数组的,所以正常注册用户的权限就是我们配置中设置的权限,对应的就是groups的值。

    那么提升权限的关键就在于更改groups中的值,因为$data由我们可控的$temp赋值,$temp的值来自于请求包,所以我们可以构造如下请求包:

    这里我们添加一组值:name="user[groups][]" value=7,让user被当作二维数组,从而groups被识别为数组,并设置数组第一个值为7,对应着Administrator的权限。

    然后发包,通过调试可以看到$temp中已经有了groups数组:

    temp

    最后创建了一个权限为Administrator的用户attacker2:

    exp

    通过存在漏洞的注册函数我们可以提权,那么在允许注册的情况下我们可不可以通过正常的注册函数来提权呢?

    通过对比这两个函数,可以发现这样一点:

    UsersControllerRegistration::register()

    UsersControllerUser::register()

    可以看到UsersControllerRegistration::register()中存储了对$requestData验证后的$data,而UsersControllerUser::register()虽然同样进行了验证,但是存储的仍是之前的$data。所以重点是validate函数是否对groups进行了过滤,我们跟进一下,在libraries/legacy/model/form.php中:

    再跟进filter函数,在libraries/joomla/form/form.php中:

    可以看到这里仅允许$fields中的值出现在$data中,而$fields中是不存在groups的,所以groups在这里被过滤掉,也就没有办法进行权限提升了。

    2016-10-27 更新

    默认情况下,新注册的用户需要通过注册邮箱激活后才能使用。并且:no-activation

    由于$data['activation']的值会被覆盖,所以我们也没有办法直接通过请求更改用户的激活状态。

    2016-11-01 更新

    感谢三好学生D的提示,可以使用邮箱激活的前提是网站开启了注册功能,否则不会成功激活。

    我们看激活时的代码,在components/com_users/controllers/registration.php中第28-99行的activate函数:

    这里可以看到仅当开启注册功能时才允许激活,否则返回403。

    3.补丁分析

    patch

    官方删除了UsersControllerUser::register()方法。

    0x02 修复方案


    升级到3.6.4

    0x03 参考


    https://www.seebug.org/vuldb/ssvid-92495

    https://developer.joomla.org/security-centre/659-20161001-core-account-creation.html

    http://www.fox.ra.it/technical-articles/how-i-found-a-joomla-vulnerability.html

    https://www.youtube.com/watch?v=Q_2M2oJp5l4

     

    作者:kk | Categories:技术分享 | Tags:
  • Joomla未授权创建用户漏洞(CVE-2016-8870) 分析

    2016-10-26

    Author: p0wd3r (知道创宇404安全实验室) Date: 2016-10-26

    0x00 漏洞概述


    1.漏洞简介

    Joomla是一个自由开源的内容管理系统,近日研究者发现在其3.4.4到3.6.3的版本中存在两个漏洞:CVE-2016-8869CVE-2016-8870。我们在这里仅分析CVE-2016-8870,利用该漏洞,攻击者可以在网站关闭注册的情况下注册用户。Joomla官方已对此漏洞发布升级公告

    2.漏洞影响

    网站关闭注册的情况下仍可创建用户,默认状态下用户需要用邮件激活,但需要开启注册功能才能激活。

    3.影响版本

    3.4.4 to 3.6.3

    0x01 漏洞复现


    1. 环境搭建

    解压后放到服务器目录下,例如/var/www/html

    创建个数据库:

    最后访问服务器路径进行安装即可。

    2.漏洞分析

    在存在漏洞的版本中我们可以看到一个有趣的现象,即存在两个用于用户注册的方法:

    • 位于components/com_users/controllers/registration.php中的UsersControllerRegistration::register()
    • 位于components/com_users/controllers/user.php中的UsersControllerUser::register()

    我们对比一下代码:

    UsersControllerRegistration::register():

    UsersControllerUser::register():

    可以看到相对于UsersControllerRegistration::register()UsersControllerUser::register()的实现中并没有这几行代码:

    这几行代码是检查是否允许注册,也就是说如果我们可以用UsersControllerUser::register()这个方法来进行注册就可以绕过这个检测。

    通过测试可知正常的注册使用的是UsersControllerRegistration::register(),请求包如下:

    虽然正常注册并没有使用UsersControllerUser::register(),但是并不代表我们不能使用。阅读代码可知,只要将请求包进行如下修改即可使用存在漏洞的函数进行注册:

    • registration.register -> user.register
    • jform[*] -> user[*]

    所以完整的复现流程如下:

    1. 首先在后台关闭注册功能,关闭后首页没有注册选项:
      no-register
    2. 然后通过访问index.php抓包获取cookie,通过看index.php源码获取token:
      get-cookie
      get-token
    3. 构造注册请求:
    4. 发包,成功注册:
      attack

    2016-10-27 更新

    默认情况下,新注册的用户需要通过注册邮箱激活后才能使用。并且:no-activation

    由于$data['activation']的值会被覆盖,所以我们也没有办法直接通过请求更改用户的激活状态。

    2016-11-01 更新

    感谢三好学生D的提示,可以使用邮箱激活的前提是网站开启了注册功能,否则不会成功激活。

    我们看激活时的代码,在components/com_users/controllers/registration.php中第28-99行的activate函数:

    这里可以看到仅当开启注册功能时才允许激活,否则返回403。

    3.补丁分析

    patch-1

    官方删除了UsersControllerUser::register()方法。

    0x02 修复方案


    升级到3.6.4

    0x03 参考


    https://www.seebug.org/vuldb/ssvid-92496

    https://developer.joomla.org/security-centre/659-20161001-core-account-creation.html

    http://www.fox.ra.it/technical-articles/how-i-found-a-joomla-vulnerability.html

    https://www.youtube.com/watch?v=Q_2M2oJp5l4

    作者:kk | Categories:安全研究技术分享 | Tags:
  • Spring Security OAuth RCE (CVE-2016-4977) 漏洞分析

    2016-10-18

    Author: p0wd3r (知道创宇404安全实验室) Date: 2016-10-17

    0x00 漏洞概述


    1.漏洞简介

    Spring Security OAuth 是为 Spring 框架提供安全认证支持的一个模块,在7月5日其维护者发布了这样一个升级公告,主要说明在用户使用Whitelabel views来处理错误时,攻击者在被授权的情况下可以通过构造恶意参数来远程执行命令。漏洞的发现者在10月13日公开了该漏洞的挖掘记录

    2.漏洞影响

    授权状态下远程命令执行

    3.影响版本

    2.0.0 to 2.0.9

    1.0.0 to 1.0.5

    0x01 漏洞复现


    1. 环境搭建


    2.漏洞分析

    首先我们查看src/resources/application.properties的内容来获取clientid和用户的密码:

    properties

    接着我们访问这个url:

    http://localhost:8080/oauth/authorize?responsetype=token&clientid=acme&redirect_uri=hellotom

    其中client_id就是我们前面获取到的,然后输入任意用户名,密码填上面的password

    点击登录后程序会返回这样一个页面:

    bug-raw

    可以看到由于hellotom对于redirect_uri来说是不合法的值,所以程序会将错误信息返回并且其中带着hellotom,那么这个不合法的值可不可以是一个表达式呢?我们再访问这个url:

    http://localhost:8080/oauth/authorize?responsetype=token&clientid=acme&redirect_uri=${2334-1}

    结果如下:

    bug-num

    可以看到表达式被执行,触发了漏洞。

    下面看代码,由于程序使用Whitelabel作为视图来返回错误页面,所以先看/spring-security-oauth/spring-security-oauth2/src/main/java/org/springframework/security/oauth2/provider/endpoint/WhitelabelErrorEndpoint.java中第18-40行:


    这里定义了Whitelabel对错误的处理方法,可以看到程序通过oauthError.getSummary()来获取错误信息,我们再次访问这个 url 并开启动态调试:

    http://localhost:8080/oauth/authorize?response_type=token&client_id=acme&redirect_uri=${2334-1}

    error

    请求中的${2334-1}已经被带入了errorSummary中,然后errorSummary被装入model中,再用SpelView进行渲染。

    我们跟进SpelViewspring-security-oauth/spring-security-oauth2/src/main/java/org/springframework/security/oauth2/provider/endpoint/SpelView.java中第21-54行:

    可以看到在render时通过helper${}中的值作为表达式,再用parser.parseExpression来执行,跟进一下replacePlaceholders这个函数,在/org/springframework/util/PropertyPlaceholderHelper.class第47-56行:

    这个函数是个递归,也就是说如果表达式的值中有${xxx}这样形式的字符串存在,就会再取xxx作为表达式来执行。

    我们看动态调试的结果:

    resolve-errosummary

    首先因为传入了${errorSummary},取errorSummary作为表达式来执行,继续执行程序:

    resolve-poc

    由于errorSummary中存在${2334-1},所以又取出了2334-1作为表达式来执行,从而触发了漏洞。所以从这里可以看出,漏洞的关键点在于这个对表达式的递归处理使我们可控的部分也会被当作表达式执行。

    3.补丁分析

    patch

    可以看到在第一次执行表达式之前程序将$替换成了由RandomValueStringGenerator().generate()生成的随机字符串,也就是${errorSummary} -> random{errorSummary},但是这个替换不是递归的,所以${2334-1}并没有变。

    然后创建了一个helper使程序取random{}中的内容作为表达式,这样就使得errorSummary被作为表达式执行了,而${2334-1}因为不符合random{}这个形式所以没有被当作表达式,从而也就没有办法被执行了。

    不过这个Patch有一个缺点:RandomValueStringGenerator生成的字符串虽然内容随机,但长度固定为6,所以存在暴力破解的可能性。

    0x02 修复方案

    作者:kk | Categories:技术分享 | Tags:
  • WordPress <= 4.6.1 使用语言文件任意代码执行 漏洞分析

    2016-10-13

    Author: p0wd3r (知道创宇404安全实验室) Date: 2016-10-09

    0x00 漏洞概述


    1.漏洞简介

    WordPress是一个以PHP和MySQL为平台的自由开源的博客软件和内容管理系统,近日在 github (https://gist.github.com/anonymous/908a087b95035d9fc9ca46cef4984e97)上爆出这样一个漏洞,在其 <=4.6.1 版本中,如果网站使用攻击者提前构造好的语言文件来对网站、主题、插件等等来进行翻译的话,就可以执行任意代码。

    2.漏洞影响

    任意代码执行,但有以下两个前提:

    1. 攻击者可以上传自己构造的语言文件,或者含有该语言文件的主题、插件等文件夹
    2. 网站使用攻击者构造好的语言文件来对网站、主题、插件等进行翻译

    这里举一个真实场景中的例子:攻击者更改了某个插件中的语言文件,并更改了插件代码使插件初始化时使用恶意语言文件对插件进行翻译,然后攻击者通过诱导管理员安装此插件来触发漏洞。

    3.影响版本

    <= 4.6.1

    0x01 漏洞复现


    1. 环境搭建

    2.漏洞分析

    首先我们来看这样一个场景:

    create_function_bug

    在调用create_function时,我们通过}将原函数闭合,添加我们想要执行的内容后再使用/*将后面不必要的部分注释掉,最后即使我们没有调用创建好的函数,我们添加的新内容也依然被执行了。之所以如此,是因为create_function内部使用了eval来执行代码,我们看PHP手册上的说明:

    eval

    所以由于这个特性,如果我们可以控制create_function$code参数,那就有了任意代码执行的可能。这里要说一下,create_function这个漏洞最早由80sec在08年提出,这里提供几个链接作为参考:

    接下来我们看Wordpress中一处用到create_function的地方,在wp-includes/pomo/translations.php第203-209行:

    根据注释可以看到该函数的作用是根据字体文件中的plural forms这个header来创建函数并返回,其中$expression用于组成$func_body,而$func_body作为$code参数传入了create_function,所以关键是控制$expresstion的值。

    我们看一下正常的字体文件zh_CN.mo,其中有这么一段:

    common

    Plural-Froms这个 header 就是上面的函数所需要处理的,其中nplurals的值即为$nplurals的值,而plural的值正是我们需要的$expression的值。所以我们将字体文件进行如下改动:payload

    然后我们在后台重新加载这个字体文件,同时进行动态调试,可以看到如下情景:

    debug

    我们payload中的)首先闭合了前面的(,然后结束前面的语句,接着是我们的一句话木马,然后用/*将后面不必要的部分注释掉,通过这样,我们就将payload完整的传入了create_function,在其创建函数时我们的payload就会被执行,由于访问每个文件时都要用这个对字体文件解析的结果对文件进行翻译,所以我们访问任何文件都可以触发这个payload:index

    tools

    其中访问index.php?c=phpinfo();的函数调用栈如下:

    call

    3.补丁分析

    目前官方还没有发布补丁,最新版仍存在该漏洞。

    0x02 修复方案


    在官方发布补丁前建议管理员增强安全意识,不要使用来路不明的字体文件、插件、主题等等。

    对于开发者来说,建议对$expression中的特殊符号进行过滤,例如:

    0x03 参考


    作者:kk | Categories:技术分享 | Tags:
  • 从老漏洞到新漏洞—iMessage 0day(CVE-2016-1843)挖掘实录

    2016-10-12

    Author: SuperHei (知道创宇404安全实验室) Date: 2016-04-11

    注:文章里“0day”在报告给官方后分配漏洞编号:CVE-2016-1843

    0x00 背景


    在前几天老外发布了一个在3月更新里修复的 iMessage xss 漏洞(CVE-2016-1764)细节 :

    他们公布这些细节里其实没有给出详细触发点的分析,我分析后也就是根据这些信息发现了一个新的 0day。

    0x01 CVE-2016-1764 漏洞分析


    CVE-2016-1764 里的最简单的触发payload: javascript://a/research?%0d%0aprompt(1) 可以看出这个是很明显javascript协议里的一个小技巧 %0d%0 没处理后导致的 xss ,这个 tips 在找 xss 漏洞里是比较常见的。

    这个值得提一下的是 为啥要用prompt(1) 而我们常用的是alert(1) ,我实际测试了下发现 alert 确实没办法弹出来,另外在很多的网站其实把 alert 直接和谐过滤了,所以这里给提醒大家的是在测试xss的时候,把 prompt 替换 alert 是有必要的~

    遇到这样的客户端的 xss 如果要分析,第一步应该看看 location.href 的信息。这个主要是看是哪个域下,这个漏洞是在applewebdata://协议下,这个原漏洞分析里有给出。然后要看具体的触发点,一般在浏览器下我们可以通过看 html 源代码来分析,但是在客户端下一般看不到,所以这里用到一个小技巧:

    这里是 html 里的 head 代码

    继续看下 body 的代码:

    那么关键的触发点:

    就是这个了。 javascript 直接进入 a 标签里的 href,导致点击执行。新版本的修复方案是直接不解析javascript://

    0x02 从老漏洞(CVE-2016-1764)到 0day


    XSS 的漏洞本质是你注入的代码最终被解析执行了,既然我们看到了document.head.innerHTML的情况,那么有没有其他注入代码的机会呢?首先我测试的肯定是还是那个点,尝试用"<>去闭合,可惜都被过滤了,这个点不行我们可以看看其他存在输入的点,于是我尝试发个附件看看解析情况,部分代码如下:

    发了个tttt.html的附件,这个附件的文件名出现在代码里,或许有控制的机会。多长测试后发现过滤也比较严格,不过最终还是发现一个潜在的点,也就是文件名的扩展名部分:

    我们提交的附件的后缀进入了 style :

    也就是可能导致 css 注入,或许我们还有机会,不过经过测试也是有过滤处理的,比如/ 直接被转为了:这个非常有意思 所谓“成也萧何,败也萧何”,如果你要注入css那么肯定给属性给值就得用: 但是:又不能出现在文件名里,然后我们要注入 css 里掉用远程css或者图片需要用/ 而/又被处理了变成了:

    不管怎么样我先注入个css测试下,于是提交了一附件名:zzzzzz.htm) 1x);color/red;aaa/((

    按推断/变为了: 如果注入成功应该是:

    当我提交测试发送这个附件的时候,我的 iMessage 崩溃了~~ 这里我想我发现了一个新的漏洞,于是我升级 OSX 到最新的系统重新测试结果:一个全新的 0day 诞生!

    0x03 后记


    当然这里还有很多地方可以测试,也有一些思路也可以去测试下,比如那个名字那里这个应该是可控制的,比如附件是保存在本地的有没有可能存在目录专挑导致写到任意目录的地方。有需求的可以继续测试下,说不定下个 0day 就是你的 :)

    最后我想说的是在分析别人发现的漏洞的时候一定要找到漏洞的关键,然后总结提炼出“模型”,然后去尝试新的攻击思路或者界面!

    0x04 参考链接


    作者:kk | Categories:技术分享 | Tags:
  • WordPress <= 4.6.1 使用主题文件触发存储型XSS 漏洞分析

    2016-10-11

    Author: p0wd3r (知道创宇404安全实验室) Date: 2016-10-08

    0x00 漏洞概述


    1.漏洞简介

    WordPress是一个以PHP和MySQL为平台的自由开源的博客软件和内容管理系统,近日研究者发现在其<=4.6.1版本中,通过上传恶意构造的主题文件可以触发一个后台存储型XSS漏洞。通过该漏洞,攻击者可以在能够上传主题文件的前提下执行获取管理员Cookie等敏感操作。

    2.漏洞影响

    在能够上传主题文件的前提下执行获取管理员Cookie等XSS可以进行的攻击,实际的攻击场景有以下两种:

    • 攻击者诱导管理员上传恶意构造的主题文件,且管理员并没有对文件进行检查
    • 攻击者拥有管理员权限可以直接上传主题文件,但既然已经有管理员权限再进行这样的攻击也就多此一举了

    3.影响版本

    <= 4.6.1

    0x01 漏洞复现


    1. 环境搭建

    2.漏洞分析

    我们先随便下载一个主题:

    然后对illdy/style.css进行如下更改:

    接着更改文件夹名字再打包:

    构造好之后我们登录后台上传该主题文件,同时开始动态调试。

    首先进入wp-admin/includes/class-theme-installer-skin.php中第55-82行:

    其中$theme_info的值如下:

    Alt text

    其中stylesheettemplate的值为我们更改的文件夹名,headers.Name为更改的style.css中的Name$theme_info中有我们可控的payload,其调用display函数后赋值给$name$name直接与html拼接,所以关键点在display函数上,动态调试跟进到wp-includes/class-wp-theme.php中第630-646行:

    由之前的调用可知,这里的$header的值为Name。首先看$this-get($header),在wp-includes/class-wp-theme.php中第594-617行:

    这里省略了与漏洞无关的部分,程序进入了$this->sanitize_header,在wp-includes/class-wp-theme.php第661-705行:

    这里执行了Name这个分支,可以看到程序使用wp_kses$value的值进行了过滤,仅允许$header_tags中的html符号,所以我们headers.Name的值<svg onload=alert(1234)>是不合法的,$value值被赋为空。

    然后程序回到了display函数,根据动态调试可以知道程序执行了$value = $this->markup_header( $header, $value, $translate );这个条件分支,再跟进,在wp-includes/class-wp-theme.php中第720-748行:

    这里我们看到由于$value在之前被赋为空,导致此处$value被重新赋值为了$this->get_stylesheet(),也就是值为<svg onload=alert(5678)>stylesheet变量。最后返回的$value赋给了$name$name再与html拼接返回给客户端,从而触发了漏洞:

    xss_js-1

    xss_html

    这个漏洞有趣的地方在于style.css中的payload其实起到的是一个障眼法的作用,正是因为<svg onload=alert(1234)>被过滤了才使$value被赋值成了我们真正的payload<svg onload=alert(5678)>。所以在构造主题文件的时候style.css和文件夹名这两个地方都要更改。

    3.补丁分析

    可能是由于利用条件十分苛刻,目前Wordpress官方还没有发布补丁,最新版Wordpress仍存在该漏洞。

    0x02 修复方案


    在官方发布补丁前,管理员应提高安全意识,不要轻易使用来路不明的主题。

    对于开发者来说建议对$name进行合法性检查,例如这样:

    0x03 参考


    作者:kk | Categories:安全研究技术分享 | Tags: