RSS Feed
更好更安全的互联网
  • Vim/Neovim 基于 modeline 的多个任意代码执行漏洞分析(CVE-2002-1377、CVE-2016-1248、CVE-2019-12735)

    2019-06-27

    作者:fenix@知道创宇 404 实验室
    日期:2019 年 6 月 11 日
    英文版本:https://paper.seebug.org/956/

    前言

    Vim 是从 vi 发展出来的一个文本编辑器。代码补全、编译及错误跳转等方便编程的功能特别丰富,在程序员中被广泛使用,和 Emacs 并列成为类 Unix 系统用戶最喜欢的文本编辑器。Neovim 是一个基于 vim 源代码的重构项目。

    2019 年 06 月 04 日,Vim & neovim 被曝出任意代码执行漏洞。攻击者通过诱使受害者使用 vim 或者 neovim 打开一个精心制作的文件,可以在目标机器上执行任意命令。

    该漏洞是由于启用了 modeline 模式导致的,Vim & neovim 历史上也多次曝出和 modeline 相关的漏洞。

    原作者已经分析的很清楚了,本文权当总结一下,顺便对历史曝出的多个漏洞做一次完整的分析。(在 vim 环境下,neovim 类似)

    modeline 详解

    既然都是和 modeline 相关的漏洞,那就有必要知道 modeline 是什么。

    vim 一共有 4 种模式:正常模式、插入模式、命令模式、可视模式。

    在正常模式中,按下 : 键,就可以进入命令模式。在命令模式中可以执行一些输入并执行一些 vim 或插件提供的指令,就像在 shell 里一样。这些指令包括设置环境、文件操作、调用某个功能、执行命令等等。例如设置不显示行号:

    如果有很多偏好设置,每次打开文件都手动设置就会显得很繁琐,这时候 .vimrc 就派上用场了,在启动 vim 时,当前用户根目录下的 .vimrc 文件会被自动加载。

    .vimrc 中的设置会对打开的所有文件生效,不便于对单个文件作个性化设置,modeline 应运而生。

    vim 的 modeline 可以让你针对每个文件进行文件级别的设置,这些设置是覆盖当前用户的 .vimrc 中的设置的。vim 默认关闭了 modeline,在 .vimrc 末尾追加 set modeline 即可打开。

    如果 modeline 打开,vim 在打开文件时会解析文件开头及末尾符合一定格式的设置行。

    格式一:

    格式二:

    为了安全考虑,在 modeline 的设置中只支持 set 命令。

    特殊的,foldexpr,formatexpr,includeexpr,indentexpr,statusline,foldtext 等选项的值可以是一个表达式,如果选项是在 modeline 中设置,表达式在沙箱中执行。沙箱实质上就是对表达式所能实现的功能做了限制,如在沙箱中不能执行 shell 命令、不能读写文件、不能修改缓冲区等等,如下:

    vim 对于沙箱的实现也很简单。

    沙箱检查函数 check_secure():

    在 libcall、luaeval 等危险指令的开头进行沙箱检查,如果发现在沙箱中调用,直接 return 掉。

    历史曝出的几个 rce 漏洞中,CVE-2002-1377 和 CVE-2019-12735 都是由于存在部分指令没有检查沙箱,导致在 modeline 模式中被滥用从而任意命令执行。下面将一一分析。

    CVE-2002-1377

    2002 年曝出的 vim 任意代码执行漏洞,影响 6.0、6.1 版本。太过古老,环境难以重现,简单说下原理。PoC 如下:

    利用 libcall 指令调用 libc 库中的 system 函数实现任意命令执行。

    现在添加了沙箱检查,modeline 下已经用不了 libcall 了:

    CVE-2016-1248

    8.0.0056 之前的 vim 未正确验证 filetype、syntax 、keymap 选项的值,受害者在 modeline 开启下打开特制的文件,则可能导致执行任意代码。

    从 github 克隆代码,checkout 到 v8.0.0055 分支,编译安装。.vimrc 的配置如下:

    验证 PoC :

    set verbose=20开启所有日志,看下调用链:

    autocommand 即“自动命令”,在发生某些事件时自动执行,类似于钩子函数。

    比如我们在命令模式中输入 :set syntax=python, vim 就会在相应目录中寻找和 python syntax 相关的 vmscript 并加载。

    如果我们在 modeline 中设置了 filetype 或者 syntax,会执行 au! FileType * exe "set syntax=" . expand("<amatch>") 自动完成上述过程。首先删除所有和 FileType 相关联的自动命令,然后调用 exe (即 execute) 执行 set syntax=filetype。execute 用于执行一个表达式字符串,由于未对 filetype 过滤,造成了命令注入。

    相关代码在 /usr/local/share/vim/vim80/syntax/syntax.vim:

    patch 8.0.0056 增加了对名称的校验。

    CVE-2019-12735

    最近刚曝出来,影响 Vim < 8.1.1365,Neovim < 0.3.6。和 CVE-2002-1377 原理类似,找到了一个新的绕过沙箱执行命令的点。source 指定的定义如下:

    :so! filepath 可以从一个文件加载 vim 命令。

    构造 PoC,将待执行的命令放在 text 部分,so! % 加载当前文件。

    [text]{white}{vi:|vim:|ex:}[white]{options}

    补丁对 source 指令添加了沙箱检查。

    总结

    Windows 记事本都任意代码执行了,Vim 怎么能被比下去 … 漏洞无处不在,谨慎打开任何来历不明文件。

    参考链接

    https://github.com/numirias/security/blob/master/doc/2019-06-04_ace-vim-neovim.md

    https://github.com/vim/vim/commit/d0b5138ba4bccff8a744c99836041ef6322ed39a


    Paper

    本文由 Seebug Paper 发布,如需转载请注明来源。本文地址:https://paper.seebug.org/952/

    作者:吴烦恼 | Categories:安全研究 | Tags:
  • Mybb 18.20 From Stored XSS to RCE 分析

    2019-06-27

    作者:LoRexxar'@知道创宇404实验室
    日期:2019年6月12日
    英文版本:https://paper.seebug.org/954/

    2019年6月11日,RIPS团队在团队博客中分享了一篇MyBB <= 1.8.20: From Stored XSS to RCE,文章中主要提到了一个Mybb18.20中存在的存储型xss以及一个后台的文件上传绕过。

    其实漏洞本身来说,毕竟是需要通过XSS来触发的,哪怕是储存型XSS可以通过私信等方式隐藏,但漏洞的影响再怎么严重也有限,但漏洞点却意外的精巧,下面就让我们一起来详细聊聊看...

    漏洞要求

    储存型xss

    • 拥有可以发布信息的账号权限
    • 服务端开启视频解析
    • <=18.20

    管理员后台文件创建漏洞

    • 拥有后台管理员权限(换言之就是需要有管理员权限的账号触发xss)
    • <=18.20

    漏洞分析

    在原文的描述中,把多个漏洞构建成一个利用链来解释,但从漏洞分析的角度来看,我们没必要这么强行,我们分别聊聊这两个单独的漏洞:储存型xss、后台任意文件创建。

    储存型xss

    在Mybb乃至大部分的论坛类CMS中,一般无论是文章还是评论又或是的什么东西,都会需要在内容中插入图片、链接、视频等等等,而其中大部分都是选择使用一套所谓的“伪”标签的解析方式。

    也就是说用户们通过在内容中加入[url][img]等“伪”标签,后台就会在保存文章或者解析文章的时候,把这类“伪”标签转化为相应的<a><img>,然后输出到文章内容中,而这种方式会以事先规定好的方式解析和处理内容以及标签,也就是所谓的白名单防御,而这种语法被称之为bbcode

    这样一来攻击者就很难构造储存型xss了,因为除了这些标签以外,其他的标签都不会被解析(所有的左右尖括号以及双引号都会被转义)。

    正所谓,有人的地方就会有漏洞。

    在这看似很绝对的防御方式下,我们不如重新梳理下Mybb中的处理过程。

    /inc/class_parse.php line 435 的 parse_mycode函数中就是主要负责处理这个问题的地方。

    当服务端接收到你发送的内容时,首先会处理解析[ img ]相关的标签语法,然后如果开启了$this->options['allow_videocode'](默认开启),那么开始解析[ video ]相关的语法,然后是[list]标签。在488行开始,会对[url]等标签做相应的处理。

    我们把上面的流程简单的具象化,假设我们在内容中输入了

    后台会首先处理[ video ],然后内容就变成了

    然后会处理[url]标签,最后内容变成

    乍一看好像没什么问题,每个标签内容都会被拼接到标签相应的属性内,还会被htmlspecialchars_uni处理,也没办法逃逸双引号的包裹。

    但假如我们输入这样的内容呢?

    首先跟入到函数/inc/class_parse.php line 1385行 mycode_parse_video

    链接经过parse_url处理被分解为

    然后在1420行,各个参数会被做相应的处理,由于我们必须保留=号以及/ 号,所以这里我们选择把内容放在fragment中。

    在1501行case youtube中,被拼接到id上

    最后id会经过一次htmlspecialchars_uni,然后生成模板。

    当然这并不影响到我们上面的内容。

    到此为止我们的内容变成了

    紧接着再经过对[url]的处理,上面的内容变为

    我们再把前面的内容简化看看,链接由

    变成了

    由于我们插入在iframe标签中的href被转变成了<a href="http://onload=alert();//">, 由于双引号没有转义,所以iframe的href在a标签的href中被闭合,而原本的a标签中的href内容被直接暴露在了标签中,onload就变成了有效的属性!

    最后浏览器会做简单的解析分割处理,最后生成了相应的标签,当url中的链接加载完毕,标签的动作属性就可以被触发了。

    管理员后台文件创建漏洞

    在Mybb的管理员后台中,管理员可以自定义论坛的模板和主题,除了普通的导入主题以外,他们允许管理员直接创建新的css文件,当然,服务端限制了管理员的这种行为,它要求管理员只能创建文件结尾为.css的文件。

    看上去好像并没有什么办法绕过,但值得注意的是,代码中先将文件名先写入了数据库中。

    紧接着我们看看数据库结构

    我们可以很明显的看到name的类型为varchar且长度只有30位。

    如果我们在上传的xml文件中构造name为tttttttttttttttttttttttttt.php.css时,name在存入数据库时会被截断,并只保留前30位,也就是tttttttttttttttttttttttttt.php.

    紧接着我们需要寻找一个获取name并创建文件的地方。

    在/admin/modules/style/themes.php 的1252行,这个变量被从数据库中提取出来。

    theme_stylesheet 的name作为字典的键被写入相关的数据。

    $mybb->input['do'] == "save_orders"时,当前主题会被修改。

    在保存了当前主题之后,后台会检查每个文件是否存在,如果不存在,则会获取name并写入相应的内容。

    可以看到我们成功的写入了php文件

    完成的漏洞复现过程

    储存型xss

    找到任意一个发送信息的地方,如发表文章、发送私信等....

    发送下面这些信息

    然后阅读就可以触发

    管理员后台文件创建漏洞

    找到后台加载theme的地方

    构造上传文件test.xml

    需要注意要勾选 Ignore Version Compatibility。

    然后查看Theme列表,找到新添加的theme

    然后保存并访问相应tid地址的文件即可

    补丁

    储存型xss

    这里的iframe标签的链接被encode_url重新处理,一旦被转义,那么[url]就不会被继续解析,则不会存在问题。

    管理员后台文件创建漏洞

    在判断文件名后缀之前,加入了字符数的截断,这样一来就无法通过数据库字符截断来构造特殊的name了。

    写在最后

    整个漏洞其实说到实际利用来说,其实不算太苛刻,基本上来说只要能注册这个论坛的账号就可以构造xss,由于是储存型xss,所以无论是发送私信还是广而告之都有很大的概率被管理员点击,当管理员触发之后,之后的js构造exp就只是代码复杂度的问题了。

    抛开实际的利用不谈,这个漏洞的普适性才更加的特殊,bbcode是现在主流的论坛复杂环境的解决方案,事实上,可能会有不少cms会忽略和mybb一样的问题,毕竟人才是最大的安全问题,当人自以为是理解了机器的一切想法时,就会理所当然得忽略那些还没被发掘的问题,安全问题,也就在这种情况下悄然诞生了...

     

    Paper

    本文由 Seebug Paper 发布,如需转载请注明来源。本文地址:https://paper.seebug.org/949/

     

    作者:吴烦恼 | Categories:安全研究 | Tags:
  • 如何打造自己的PoC框架-Pocsuite3-框架篇

    2019-05-15

    作者:w7ay@知道创宇404实验室
    English version: https://paper.seebug.org/914/
    相关阅读:如何打造自己的PoC框架-Pocsuite3-使用篇

    本节笔者将按照Pocsuite框架结构以及工程化实践,来实现一款自己的PoC框架。为了开一个好头,我们先取一个好听的名字,想威武霸气一些可以取上古神器之类的,诸如轩辕夏禹赤霄干将,若怀着对游戏的热爱也可以有山丘之王(Mountain King)剑圣(BladeMaster)月之女神(Priess Of the moon)。由于笔者比较懒,我们就取一个朴素的名字:AirPoc,中文名叫它"空气炮"吧。

    名称取好了,我们还要幻想一下大饼。这里请充分发挥想象力,幻想它的功能,你要记住,没有我们实现不了的功能,如果有,打死产品manager即可。

    这里不妨开下脑洞,为了组建兔子安全联盟,我们计划开发一款基于区块链的PoC验证框架AirPoc,限定只对"兔子安全联盟”范围内的网站进行安全检查,由一个AirPoc节点检查出了存在漏洞的地址,将URL和PoC共享到区块中,再由随机的其他节点验证,验证成功则获得"空气币",而被检测到的网站所有者则需要支付"空气币"作为报酬。

    虽然只是暂时的幻想,但是产品小哥哥也略带激动整理出了我们需要的功能。

    1. 使用简单,不要有太多的命令,可以跨平台使用
    2. 人多力量大,能让更多人参与进来的
    3. 能简单操作就能内置到其他产品上
    4. 验证速度与验证准确率极高!
    5. 我也不知道什么好,总之你跑起来能出东西就行!

    当然,这位产品小哥哥可能怕被打,没有将分布式,区块链的概念加入进来。

    具体细节

    下面就由笔者来具体实现由笔者兼职的产品manager随便一想(挖坑)的东西。我们逐一分析问题,并给出最后的解决方案。

    说到使用简单,我们就任性的选择使用Python了,不信你看看Python之父的头发。在安装了Python之后,也可以一份代码多处使用,但为了足够的简单与原生,我们决定尽量少使用Python的第三方包。而目前Python最新版为3.7,我们就以此为例。

    国外的众多开源安全项目都有不少人参与,像Metasploit

    image-20190425142853330

    Sqlmap

    image-20190425142829862

    Routersploit

    image-20190425142732368

    能贡献一份代码到上面可能是安全研究人员最想做的事情吧。

    所以笔者有个想法是AirPoc的PoC仓库可以开源到GitHub,并且能够在线调用上面的PoC,这样也不会为了PoC的更新而烦恼了。

    内置到其他产品也更是容易,如果是Python类的软件,可以直接把AirPoc当做包来调用,如果其他软件,AirPoc可以开放一个RPC接口提供使用,如果不想要Python的环境,也可以通过pyinstaller之类的工具打包,我们的设计原则是尽量不依赖其他第三方库,所以也会避免很多奇奇怪怪的问题。

    想要实现验证速度与验证准确率极高,我们要做好多线程或协程的并发模型,这里我们会在后面在详细叙述。

    最后,"我也不知道什么好,总之你跑起来能出东西就行!",如果上面的事情我们都做好了,这个应该就是水到渠成的了~

    AirPoc的框架

    在完成这个"宏伟计划"之前,我们也需要设计一下整体的代码框架。作为一名代码洁癖患者,一个良好的代码结构,是万里长征的第一步。我们建立如下的目录结构,env是虚拟环境,建立两个目录libpocslib用于存储之后的相关核心文件,pocs用于存储poc文件,和一个文件main.py用作初始入口。

    就像盖大楼需要打好地基,接下来完成基础框架,我们可以先不用写具体的功能,但是了解作为"地基"的函数的意义。如下,在main.py文件中如下代码,一个初始的框架就完成了。

     

    image-20190429110505553

    但是,正如你所见,版本号和我的比特币钱包的数字竟然差不多,我们还要给它加些料。

    单例模式

    在我们软件的初始化的工程中,我们需要得到很多环境相关的信息。比如当前执行的路径是哪?poc目录在哪?我们输出结果文件输出到哪个路径等等。

    它们有一个共同的特定是,它们只需要加载一次,在后面使用中直接拿来用就行了。这种模式在软件设计模式中有一个单独的名词,"单例模式"。

    幸运的是python的模块就是天然的单例模式,因为模块在第一次导入时,会生成 .pyc 文件,当第二次导入时,就会直接加载 .pyc 文件,而不会再次执行模块代码。因此,我们只需把相关的函数和数据定义在一个模块中,就可以获得一个单例对象了。

    我们在lib目录里面新建一个data.py用于存储这些信息。同时将版本信息也放到这里来。

     

    为了更好的来表示这些常量,我们用PEP8标准里的规范,统一约定用大写和下划线来表示常量。为了说明与之前的区别,我们象征性的将VERSION减一个0,来表达我们的比特币又增长了10倍。

    动态加载

    在解决完我们相关的环境问题后,我们在看看如何动态加载模块。在具体细节里我们说过,我们期望PoC能够从本地或者远程网站(如GitHub)上加载。

    这里又得分成两种情况,如果是通过文件路径加载动态加载的模块,可以直接用__import__()来加载,但是如果要远程加载,可能就又会复杂一点,根据python的相关文档,我们要自己实现"查找器"与"加载器" https://docs.python.org/zh-cn/3/reference/import.html

    当然,你也可以从远程保存到本地后,按照本地加载模式进行加载。但是Pocsuite已经有完整的加载器代码了,我们可以直接拿来用。

    新建lib/loader.py文件

     

    具体如何实现的我们可以不用关心,我们只需要知道,其中我们可以用load_string_to_module来从源码中加载模块了。如果你有兴趣了解具体的实现,可以参考上面的python官方文档。

    规则的制定

    从文件或者远程加载好模块后,就可以准备运行的相关事宜了。我们需要对PoC做一个规则的统一约定,让程序更好的调用它们。

    你可以将规则定义的详细,也可以一切从简,主要是看使用场景。而前面也提到,为了保护"安全联盟"的安全问题,所以我们需要PoC更够比较简单的快速编写。

    同时我们还需要考虑如果PoC需要多个参数如何处理?笔者的规则是这样定义的。

     

    在PoC文件中定义一个verify函数用作验证使用,arg作为普通的参数传递,当需要传递较多的参数时,从kwargs中接收。在PoC验证成功后,也只需要返回一个字典即可,如果验证失败,返回FalseNone即可。字典内容由PoC编写者制定,给予编写者最大的灵活空间。

    但是注意!PoC的质量就需要依靠编写者的维护。

    V0.01

    我们最终要实现的目标是,设置好目标,程序自动加载指定的一个或多个PoC或全部的PoC,逐个检测目标。剩下的部分就是怎样将这些功能串联在一起了。

    前面我们已经实现了AirPoc的基础框架,现在只需要在其基础上具体实现功能即可。

    为了测试的方便,我们先在pocs目录下按照之前定义的规则建立两个简陋的PoC。

    image-20190429164121695

    image-20190429164143909

    现在,main.py中的代码如下

     

    我们的版本也来到了0.01,它已经是一个"成熟的”能自己跑PoC的框架了。

    image-20190429172118745

    多线程模型

    为了让我们的框架运行得更快一点,我们使用多线程来处理每个PoC,因为我们处理的任务大多是I/O密集型任务,所以我们也不用太纠结python是不是伪线程这个问题。

    多线程模型中最简单的一种是生产者/消费者的模型,启动多个线程来共同消费一个队列就行了。新建lib/threads.py

     

    值得注意的一点是,我们并没有使用Python线程中推荐的join()来阻塞线程,因为使用join()的话,python将无法响应用户输入的消息了,会导致Ctrl+C退出时没有任何响应,所以以while循环的方式来阻塞线程。

    接着将主程序改造成多线程的模式,将原start()中的"消费者"提取出来,单独用作一个函数,用队列接收数据即可。如下

     

    另外,线程数量是我们可配置的,我们将它改成从配置中读取。

     

    再次运行,会发现比以前快很多!

    image-20190430102952036

    统一网络请求

    这是我们整个框架的最后一个部分,如何来统一网络请求。有时我们需要让我们的PoC框架发出的网络请求中统一一下代理,UA头等等的设置,这需要我们框架进行统一的处理。在实现我们的目的之前,我们还需要在框架里做一个约定,约定我们的网络请求都需要统一使用requests来进行发包。开始时我们说到,我们会尽量不使用第三方模块,但是requests模块实在太好用了,我们将它排除在外...

    Python语言动态的机制,我们可以很容易在使用一个函数之前Hook它,将它原始的方法重定向到我们自定义的方法中,这是我们能够统一网络请求的一个前提。

     

    image-20190430112557108

    通过hook一个函数来达到我们自己的目的。

    像sqlmap这类工具,基于python内置的urllib模块,但是有大量的代码都在处理在了网络请求方面,甚至为了处理chunked发包的问题,hook重写了更底层的httplib库。

    pocsuite为了统一调度网络请求,hook了requests模块的相关方法。我们可以具体参考其中的代码。

    pocsuite3/lib/request/patch/__init__.py代码很清晰的说明了hook的函数

     

    如果你看过requests的源码,会知道这里面的重点是看它如何hook seesion函数的。

    pocsuite3/lib/request/patch/hook_request.py

     

    它重写了session_request函数的方法,让其中可以自定义我们自定义的文件头等信息。上述代码可能需要你看过requests才会对他有所理解,不过没关系,我们还是以拿来主义的精神直接用即可。

    为了达到此目的以及更好的优化框架结构,我们还需要做一些小调整。

    新建lib/requests.py

     

    同时在config中预留requests的接口

    image-20190430115617047

    以及init的时候执行我们的hook。

    image-20190430115652364

    我们新编写一个PoC,用这个网站测试一下 最后的效果 http://www.httpbin.org/get

    pocs/poc.py

     

    image-20190430130417913

    效果很好,但是如果加上https的网站,就有一个警告信息。

    image-20190430130730241

    同样参考Pocsuite的方法禁用掉warning信息

     

    最后有仪式感的将版本号变更为0.1,AirPoc的框架部分大体完成了。

    最后

    AirPoc的很多结构思想都来源于Pocsuite,如果直接阅读Pocsuite,也许能收获很多东西。目前AirPoc v0.1基础框架已经差不多完成了,已经可以从本地加载一个或多个PoC,进行批量测试。后面我们再尝试些更好玩的,如何验证无回显的情况,如何生成shellcode,以及如何操作回连的shell,敬请期待下节《功能篇》~。

    AirPoc下载:https://images.seebug.org/archive/airpoc.zip


    Paper

    本文由 Seebug Paper 发布,如需转载请注明来源。本文地址:https://paper.seebug.org/913/

    作者:吴烦恼 | Categories:安全研究技术分享 | Tags:
  • WebLogic RCE(CVE-2019-2725)漏洞之旅

    2019-05-05

    作者:Badcode@知道创宇404实验室
    时间:2019年4月30日
    English version: https://paper.seebug.org/910/

    417

    2019年4月17日,CNVD 发布《关于Oracle WebLogic wls9-async组件存在反序列化远程命令执行漏洞的安全公告》,公告指出部分版本WebLogic中默认包含的wls9_async_response包,为WebLogic Server提供异步通讯服务。由于该WAR包在反序列化处理输入信息时存在缺陷,攻击者可以发送精心构造的恶意 HTTP 请求,获得目标服务器的权限,在未授权的情况下远程执行命令。

    418

    2019年4月18日,开始应急。因为这个漏洞当时属于0day,也没有补丁可以参考,只能参考公告内容一步一步来看了。首先看到公告里提到的wls9_async_response.war包,看下web.xml里的url。

    看到/AsyncResponseService,尝试访问一下,404。之后看到weblogic.xmlweblogic-webservices.xml

    访问下_async/AsyncResponseService

    可以正常访问,再结合公告中的漏洞处置建议,禁止 /_async/* 路径的URL访问,可以大概率猜测,漏洞入口在这里。

    weblogic-webservices.xml中有一个类,weblogic.wsee.async.AsyncResponseBean,跟进去这个类,发现在wseeclient.jar里面

    而后我在这个类里面的方法下断点,然后构造一个普通的SOAP消息,发送。

    断点没有debug到。最后我把wsee/async所有类的所有方法都下了断点,重新发送消息,成功在AsyncResponseHandler类中的handleRequest拦截到了。

    继续流程,String var2 = (String)var1.getProperty("weblogic.wsee.addressing.RelatesTo");这个步骤一直取不到值,导致流程结束。为了解决这个问题,翻了不少资料,最后找到一个类似的例子,可以使用<ads:RelatesTo>test</ads:RelatesTo>weblogic.wsee.addressing.RelatesTo赋值。

     

    之后流程就能够继续下去了,我一直以为漏洞的关键点在这里,因为这个wsee.async下面的几个类中有readObject方法,我一直尝试着通过AsyncResponseHandler跳到readObject方法,而后就卡在这里,后面的流程就不写了,对这个漏洞来说是错的,上面写的这些猜测和流程都是正确的。

    419

    2019年4月19日,和我一起应急的师傅给我发了一张截图。

    看到这截图里面的RelatesTo,我还以为之前的推测没有错,只是没有构造好。

    全局搜索UnitOfWorkChangeSet这个类,之后在这个类中下断点。

    根据截图,构造一个类似的,然后发送

    在这个类中debug到了。

    看到了日思夜想的readObject,有了反序列的点,自然要找利用链了,目前 WebLogic 下面 commoncollections 相关的利用链已经是无法使用了,WebLoigc 依赖的common-collections版本已经升级了,先找个Jdk7u21测试一下,将生成的 payload 转换成 byte,发送。

    可以看到,成功地执行了命令。但是这个利用链限制太大了,基本没啥用。我想起去年应急过的一个WebLogic 反序列漏洞,CVE-2018-3191,既然jdk7u21都不受黑名单限制,想来CVE-2018-3191也是一样可以利用的。

    猜测没有错误,CVE-2018-3191也是能够利用的,这个漏洞也终于有点"危害"了。和 pyn3rd 师傅讨论一下有没有其他利用链,仔细翻下黑名单,除了CVE-2018-3191,就只有新的jython利用链(CVE-2019-2645)了,由 Matthias Kaiser大佬提交的,但是目前这个还有没有公开,所以这个利用链也没法使用。

    有了正确答案,就可以看下之前的猜测哪里出了问题。

    回到AsyncResponseHandler类中的handleRequesthandleRequest的上一步,HandlerIterator类中的handleRequest方法

    会遍历this.handlers,然后调用每个handlerhandleRequest去处理用户传入的SOAP Message。

    可以看到,AsyncResponseHandler仅仅只是21个handler之中的一个,而weblogic.wsee.addressing.RelatesTo的赋值就是在ServerAddressingHandler中完成的,有兴趣的可以去跟一下。这里面有一个非常重要的handler--WorkAreaServerHandler,看名字可能觉得眼熟,看到里面的handleRequest方法可能就不淡定了。

    之后的流程就和CVE-2017-10271是一样的了,关于这个漏洞的分析可以参考廖师傅的文章

    跟到这里就可以看出来了,这个url只是CVE-2017-10271漏洞的另外一个入口而已。这也是后期导致假PoC泛滥的一个原因。整个流程大概如下:

    那么问题来了,这个PoC是如何绕过CVE-2017-10271的黑名单的呢?

    首先来看一下CVE-2017-10271的补丁,会将传入的数据先调用validate校验,通过之后才交给XMLDecoder

     

    可以看到,objectnewmethod这些标签都被拦截了,遇到直接抛出错误。void标签后面只能跟indexarray标签后面可以跟class属性,但是类型只能是byte类型的。其中,过滤object标签是CVE-2017-3506的补丁,剩下的过滤是针对CVE-2017-10271的补丁。

    如果仔细看了黑名单的,就不难发现,外面流传的很多PoC都是假的,就是新url入口+老的payload,这样的组合是没有办法绕过这个黑名单的。

    绕过这个黑名单的关键是class标签,可以从官方的文档来了解一下这个标签。

    class标签可以表示一个类的实例,也就是说可以使用class标签来创建任意类的实例。而class标签又不在WebLogic 的黑名单之内,这才是这个漏洞最根本的原因。4月26日,Oracle 发布这个漏洞的补丁,过滤了class标签也证实了这点。

    既然漏洞的原因是绕过了CVE-2017-10271的黑名单,那么wls-wsat.war也是应该受影响的。

    测试一下,没有问题。

    这说明,CNVD的公告写的影响组件不全,漏洞处置建议也写的不全面,要通过访问策略控制禁止 /_async/* 及 /wls-wsat/* 路径的URL访问才行,之后我们也同步给了CNVD,CNVD发了第二次通告

    421

    2019年4月21日,准备构造出这个漏洞的检测PoC,能够使用class标签来创建类的实例,我首先考虑的是构造java.net.Socket,这也引出了一个JDK版本的坑。我测试的是jdk6,参考之前的PoC,可以这么构造

    ceye成功接收到请求,也说明Socket实例创建成功了。

    我把上面的检测PoC在 jdk 7上测试,竟然失败了,一直爆找不到java.net.Socket这个类错误,让我一度以为这个漏洞只能在 jdk 6 下面触发,后来仔细对比,发现是换行符的问题,也就是这样写才对。

    不带换行符的在6和7下面都能生成实例。其实这个问题在最早测试 CVE-2018-3191 payload的时候就已经发生过,pyn3rd师傅问我xml payload是怎么生成的,我说用的拼接,直接System.out.println输出的,都带了换行符,我因为当时跑weblogic的jdk是jdk6,所以没有问题,但是 pyn3rd 师傅的环境是 jdk7 的,没测试成功,只觉得是PoC写法不同造成的问题,后来师傅自己解决了,这里也没沟通,埋下了一个大坑,导致我后面踩进去了。

    422

    2019年4月22日,pyn3rd 师傅测试 WebLogic 12.1.3没成功,发现是12的版本没有oracle.toplink.internal.sessions.UnitOfWorkChangeSet这个类,所以没办法利用。尝试着构造新的exp,目前的情况是,能够创建类的实例,但是调用不了方法。自然想起com.sun.rowset.JdbcRowSetImpl这个类。

    这个是CVE-2017-10271的一种触发方法。之前的黑名单提过,void标签后面只能跟index,所以上面这个payload肯定会被黑名单拦截。尝试使用class标签重写上面的payload。

    构造的过程中,在跟底层代码的时候,发现 jdk 6和 jdk 7处理标签的方式不同。

    jdk 6使用的是com.sun.beans.ObjectHandler

    能用的有stringclassnullvoidarrayjavaobject和一些基本类型标签(如int)。

    jdk7 使用的是com.sun.beans.decoder.DocumentHandler

    可以看到,和jdk6差异不小,例如,jdk 6不支持newproperty等标签。

    我在用jdk 6 的标签构造的时候,一直没构造成功,直到我看到jdk 7 的源码里面的property,这不就是我想要的么,而且这个标签还不在 WebLogic 的黑名单内。所以重写上面的payload如下

    可以看到,没有触发黑名单,成功的执行了命令,而且没有依赖 WebLogic 内部的包,10.3.6和12.1.3都可以通用。遗憾的是,这个payload的打不了 jdk 6的,因为 jdk 6 不支持 property标签。期望有大佬能写出6也能用的。

    423

    2019年4月23日,在CNVD发出通告,各大安全公司发出漏洞预警之后,之前提过的新url+老payload的这种模式的PoC和exp纷纷出炉。不仅是国内,国外也很热闹,很多人表示测试成功,但是都是在无补丁的情况下测试的。Oracle 官网下载的 WebLogic 都是没有安装补丁的,Oracle的补丁是单独收费的,如果安装了 CVE-2017-10271 的补丁,这些PoC和exp都是没有办法触发的,绕过不了黑名单。

    426

    2019年4月26日,Oracle 官方发布紧急补丁,并为该漏洞分配编号CVE-2019-2725。

    427

    2019年4月27日,pyn3rd 师傅说12.1.3版本的exp也有人弄出来了,用的是org.slf4j.ext.EventData

     

    看下这个类的构造方法,直接将传入的xml交给XMLdecoder处理,太粗暴了...

    相当于经过了两次XMLdecode,所以外层用<class>绕过,内层直接标记为纯文本,绕过第一次过滤,第二次 XMLdecode不经过WebLogic 黑名单,直接被JDK解析反序列化执行。

    这种exp也是最完美的,没有jdk版本限制,不需要外连,可惜的是只能打12.1.3版本。

    430

    2019年4月30日,在其他大佬手中看到了这个漏洞的其他利用方式,没有 weblogic和 jdk的版本限制,比上面的几种利用方式都更完善。这种利用方式我之前也看到过,就是Tenable 发的演示视频,当时没想明白,看了大佬的利用方式之后,才明白自己忽略了什么。构造方式可以参考CVE-2017-17485,我之前构造exp的时候也没有往这方面想,这或许就是黑哥说的积累不够吧。

    总结

    • 针对这次漏洞,Oracle 也是打破了常规更新,在漏洞预警后不久就发布了补丁,仍然是使用黑名单的方式修复。(吐槽一下,这么修复,这个功能还能用么?)
    • 此次的漏洞事件中,也看到了安全圈的乱象,漏洞都没有经过完全的验证,就直接发错误的分析文章和假PoC,误导大众。
    • 在这个漏洞应急的过程中,从无到有,从缺到圆,踩了很多坑,也学习到了很多姿势,也看到了自己和大佬的差距。最后感谢漏洞应急过程中几位师傅的交流和指点。

    参考链接

     

    Paper

    本文由 Seebug Paper 发布,如需转载请注明来源。本文地址:https://paper.seebug.org/909/

    作者:吴烦恼 | Categories:安全研究技术分享 | Tags:
  • WebLogic CVE-2019-2647、CVE-2019-2648、CVE-2019-2649、CVE-2019-2650 XXE漏洞分析

    2019-05-05

    作者:Longofo@知道创宇404实验室
    时间:2019年4月26日

    Oracle发布了4月份的补丁,详情见链接(https://www.oracle.com/technetwork/security-advisory/cpuapr2019-5072813.html#AppendixFMW)

    @xxlegend 在《Weblogic CVE-2019-2647等相关XXE漏洞分析》分析了其中的一个XXE漏洞点,并给出了PoC。刚入手java不久,本着学习的目的,自己尝试分析了其他几个点的XXE并构造了PoC。下面的分析我尽量描述自己思考以及PoC构造过程,新手真的会踩很多莫名其妙的坑。感谢在复现与分析过程中为我提供帮助的小伙伴@Badcode,没有他的帮助我可能环境搭起来都会花费一大半时间。

    补丁分析,找到漏洞点

    根据JAVA常见XXE写法与防御方式(参考https://blog.spoock.com/2018/10/23/java-xxe/),通过对比补丁,发现新补丁以下四处进行了setFeature操作:

    应该就是对应的四个CVE了,其中ForeignRecoveryContext@xxlegend大佬已经分析过了,这里就不再分析了,下面主要是分析下其他三个点

    分析环境

    • Windows 10
    • WebLogic 10.3.6.0
    • Jdk160_29(WebLogic 10.3.6.0自带的JDK)

    WsrmServerPayloadContext 漏洞点分析

    WsrmServerPayloadContext修复后的代码如下:

    可以看到进行了setFeature操作防止xxe攻击,而未打补丁之前是没有进行setFeature操作的

    readExternal在反序列化对象时会被调用,与之对应的writeExternal在序列化对象时会被调用,看下writeExternal的逻辑:

    var1就是this.formENdpt,注意var5.serialize可以传入三种类型的对象,var1.getEndptElement()返回的是Element对象,先尝试新建一个项目构造一下PoC:

    结构如下

    test.xml内容如下,my.dtd暂时为空就行,先测试能否接收到请求:

    运行PoC,生成的反序列化数据xxe,使用十六进制查看器打开:

    发现DOCTYPE无法被引入

    我尝试了下面几种方法:

    • 在上面说到var5.serialize可以传入Document对象,测试了下,的确可以,但是如何使getEndptElement返回一个Document对象呢?
      • 尝试了自己创建一个EndpointReference类,修改getEndptElement返回对象,内容和原始内容一样,但是在反序列化时找不到我创建的类,原因是自己建的类package与原来的不同,所以失败了
      • 尝试像Python那样动态替换一个类的方法,貌似Java好像做不到...
    • 尝试了一个暴力的方法,替换Jar包中的类。首先复制出Weblogic的modules文件夹与wlserver_10.3\server\lib文件夹到另一个目录,将wlserver_10.3\server\lib\weblogic.jar解压,将WsrmServerPayloadContext.class类删除,重新压缩为weblogic.Jar,然后新建一个项目,引入需要的Jar文件(moduleswlserver_10.3\server\lib中所有的Jar包),然后新建一个与WsrmServerPayloadContext.class同样的包名,在其中新建WsrmServerPayloadContext.class类,复制原来的内容进行修改(修改只是为了生成能触发xml解析的数据,对readExternal反序列化没有影响)。WsrmServerPayloadContext.class修改的内容如下:
    • 经过测试第二种方式是可行的,但是好像过程略复杂。然后尝试了下新建一个与原始WsrmServerPayloadContext.class类同样的包名,然后进行修改,修改内容与第二种方式一样测试这种方式也是可行的,比第二种方式操作起来方便些

    构造新的PoC:

     

    查看下新生成的xxe十六进制:

    DOCTYPE被写入了

    测试下,使用T3协议脚本向WebLogic 7001端口发送序列化数据:

    漂亮,接收到请求了,接下来就是尝试下到底能不能读取到文件了

    构造的test.xml如下:

    my.dtd如下(my.dtd在使用PoC生成反序列化数据的时候先清空,然后,不然在dbBuilder.parse时会报错无法生成正常的反序列化数据,至于为什么,只有自己测试下才会明白):

    运行PoC生成反序列化数据,测下发现请求都接收不到了...,好吧,查看下十六进制:

    %dtd;%send;居然不见了...,可能是因为DOM解析器的原因,my.dtd内容为空,数据没有被引用。

    尝试debug看下:

    可以看到%dtd;%send;确实是被处理掉了

    测试下正常的加载外部数据,my.dtd改为如下:

    gen.xml为:

    debug看下:

    可以看到%dtd;%send;被my.dtd里面的内容替换了。debug大致看了xml解析过程,中间有一个EntityScanner,会检测xml中的ENTITY,并且会判断是否加载了外部资源,如果加载了就外部资源加载进来,后面会将实体引用替换为实体申明的内容。也就是说,我们构造的反序列化数据中的xml数据,已经被解析过一次了,而需要的是没有被解析过的数据,让目标去解析。

    所以我尝试修改了十六进制如下,使得xml修改成没有被解析的形式:

    运行PoC测试下,

    居然成功了,一开始以为反序列化生成的xml数据那块还会进行校验,不然反序列化不了,直接修改数据是不行的,没想到直接修改就可以了

    UnknownMsgHeader 漏洞点分析

    WsrmServerPayloadContext差不多,PoC构造也是新建包然后替换,就不详细分析了,只说下类修改的地方与PoC构造

    新建UnknownMsgHeader类,修改writeExternal

    PoC如下:

     

     

    运行PoC测试下(生成的步骤与第一个漏洞点一样),使用T3协议脚本向WebLogic 7001端口发送序列化数据:

    WsrmSequenceContext 漏洞点分析

    这个类看似需要构造的东西挺多的,readExternalwriteExternal的逻辑也比前两个复杂些,但是PoC构造也很容易

    新建WsrmSequenceContext类,修改

    PoC如下:

     

     

    测试下,使用T3协议脚本向WebLogic 7001端口发送序列化数据:

    最后

    好了,分析完成了。第一次分析Java的漏洞,还有很多不足的地方,但是分析的过程中也学到了很多,就算是一个看似很简单的点,如果不熟悉Java的一特性,会花费较长的时间去折腾。所以,一步一步走吧,不要太急躁,还有很多东西要学。

     

    Paper

    本文由 Seebug Paper 发布,如需转载请注明来源。本文地址:https://paper.seebug.org/906/

    作者:吴烦恼 | Categories:安全研究技术分享 | Tags:
  • 如何打造自己的PoC框架-Pocsuite3-使用篇

    2019-04-25

    作者:w7ay@知道创宇404实验室
    Engilish version: https://paper.seebug.org/905/

    相比于无聊的用法介绍,我更想说一下Pocsuite3为什么会有这些功能以及是如何实现的。如果你也想制造一款类似的工具,Pocsuite3的一些思想或许能够帮助到你。本文同时也是记录Pocsuite3开发过程中的一些思考与理解。

    简介

    Pocsuite 是由知道创宇404实验室打造的一款开源的远程漏洞测试框架。它是知道创宇安全研究团队发展的基石,是团队发展至今一直维护的一个项目,保障了我们的 Web 安全研究能力的领先。

    你可以直接使用 Pocsuite 进行漏洞的验证与利用;你也可以基于 Pocsuite 进行 PoC/Exp 的开发,因为它也是一个 PoC 开发框架;同时,你还可以在你的漏洞测试工具里直接集成 Pocsuite,它也提供标准的调用类。

    Pocsuite3是完全由Python3编写,支持Windows/Linux/Mac OSX等系统,在原Pocsuite的基础上进行了整体的重写与升级,使整个框架更具有操作性和灵活性。

    巨人的肩膀

    Pocsuite3在编写时参考了很多市面上的开源框架以及流行成熟的框架,在代码工程结构上参考了Sqlmap,Pocsuite-console模式则参照了routersploit与metasploit,所以PoC的代码格式和以前有些差别(但是尽量克制了大的改动)。Pocsuite3也提供了非常简单的接口调用,可以集成到其他安全工具内部。

    下载

    Pip 安装

    安装有两种,pip和直接运行源码。

    将使用Pocsuite3最新版。

    执行

    检验安装效果。

    源码安装

    如果你自信能折腾的话,可以下载源码使用,这也是我们推荐的方式,因为pip的更新可能会慢于github,

    同时需要安装两个依赖

    如果同时也是Windows系统,除了上面的依赖还需要安装一个

    最后

    检验安装效果。

    另外需要注意的是,两种安装方式只可以取其一,不可同时安装。建议使用源码安装的方式。

    一般使用帮助

    大多数情况,-h可以帮助你了解Pocsuite支持的功能。

    一个简单的测试

    将使用ZoomEye搜索ecshop并使用ecshop_rce.py探测,指定线程数量为5

    Pocsuite的运行模式默认是verify验证模式,此时对目标影响最小,也有attackshell模式,对目标进行相关攻击与shell反弹(当然需要PoC的支持,Pocsuite的PoC编写格式预留了这三种模式的接口,并且有很多内置API帮助实现这三种接口)

    Shell模式

    Pocsuite3新增加了shell模式的设定,当你选择了此函数,Pocsuite3将会监听一个端口,并等待目标的反连。我们提供了各种语言用于反连的payload,以及用于生成在Windows/Linux平台下可执行的shellcode。

    从配置文件运行

    有时候命令行命令太多,有些参数的重用性比较高,Pocsuite也提供了从配置文件中运行的方法。

    我们以redis未授权访问漏洞为例,我们修改这个文件pocsuite.ini

    线程也调整一下,RUN!

    由于开启了comparsion参数,我们可以看到更多的信息

    1

    如果你同时还是Zoomeye VIP,搜集目标的同时也能够识别出蜜罐信息。目前只有通过Zoomeye接口获取的数据才能有蜜罐的标识。Shodan、Censys暂未开放相关API接口。

    插件系统

    Pocsuite支持了插件系统,按照加载目标(targets),加载PoC(pocs),结果处理(results)分为三种类型插件。

    Targets插件

    除了本身可以使用-u-f加载本地的目标之外,你可以编写一个targets类型插件从任何你想加载的地方加载目标(eg:Zoomeye、Shodan)甚至从网页上,redis,都可以。Pocsuite3内置了四种目标加载插件。

    从上文可以看出,如果使用了搜索dork—dork—dork_zoomeye—dork_shodan—dork_censys,相关插件将自动加载,无需手动指定。

    Pocs插件

    原来只能通过从seebug中调用插件,现在将这种方式抽离出来作为插件,将允许从任何能够访问的地方调用,甚至写一个插件在github上维护一个仓库调用都行。

    Demo:

    https://github.com/knownsec/pocsuite3/blob/master/pocsuite3/plugins/poc_from_redis.py

    https://github.com/knownsec/pocsuite3/blob/master/pocsuite3/plugins/poc_from_seebug.py

    Results-plugin

    Results插件允许对扫描的结果进行处理,可以参考内置的两个插件,保存结果为html与保存结果为txt。Results插件的结果是实时的,具体可以看plugins/file_record.py的实现方式。

    https://github.com/knownsec/pocsuite3/blob/master/pocsuite3/plugins/html_report.py

    https://github.com/knownsec/pocsuite3/blob/master/pocsuite3/plugins/file_record.py

    调用插件

    通过--plugins在后面指定插件名称,多个插件可以用,分割。例如--plugins html_report将会生成HTML报表格式文档。

    内置API

    基于我们漏洞应急的积累,基本上Pocsuite内置的API接口可以做到PoC编写的全覆盖了。很多API接口我们下一章再说,这里说两个比较有趣的案例。

    Shellcode生成支持

    在一些特殊的Linux和Windows环境下,想得到反弹shell条件比较困难。为此我们制作了用于在Windows/Linux x86 x64环境下的用于反弹的shellcode,并制作了接口支持,你在只需要拥有命令执行权限下便可以自动将shellcode写入到目标机器以及执行反弹shell命令。Demo Poc:https://github.com/knownsec/pocsuite3/blob/master/pocsuite3/pocs/thinkphp_rce2.py

    HTTP服务内置

    如果你们还对Hacking Jenkins Part 2 - Abusing Meta Programming for Unauthenticated RCE! 有印象。多么完美的漏洞,但是在编写PoC的时候我们遇到了困难,verify模式我们可以轻松用Ceye来识别,但是attack模式与shell模式我们就必须要制作自己的Jar并将它上传到服务器上面!

    为此我们制作Jar格式打包的API以及HTTP服务API,在后面的众多越来越难以自动化的PoC编写中,会发现它是如此好用。

    附 Jenkins Abusing Meta Programming for Unauthenticated RCE(CVE-2019-1003000) with Pocsuite3 演示视频。

    https://www.youtube.com/watch?v=5P7WWlqYt4U

    自定义参数传递

    随着编程人员的安全意识逐渐提高,会发现以前一条链接就可以获取RCE的时代已经过去了。越来越多的漏洞转向需要一定"权限"才能触发。为此,我们需要在Pocsuite3预留参数接口。

    在尽量保持原有PoC格式的前提下,我们增加了一个_options方法,用于指定用户传递的参数。DemoPoc: https://github.com/knownsec/pocsuite3/blob/master/tests/login_demo.py

    我们定义了在Poc中需要传递usernamepassword两个参数,为了使用的方便,可以直接在命令行模式下如下

    是的,就是这么简单。可能你会问如果PoC中定义的参数与Pocsuite自带的参数名冲突了如何解决?我们的解决办法是不允许定义冲突的参数名,Pocsuite在启动时就会检查,如果有冲突的参数名会提示你修改PoC中的自定义参数名称。

    Console模式

    在某些情况下,我们也考虑到了可交互的命令模式(黑客的仪式感)。并且它完全能兼容命令行模式下的PoC,如果你在Linux或Mac下使用它,将得到更好的体验。

    一些Tips:

    • 在此模式下多用help可以明白更多
    • 加载PoC插件时,可以直接use + 数字,更简单方便,当然输入完整路径也可以,按下Tab会自动补全。
    • 有一些命令别名没有在help中显示,作为彩蛋等待使用者发现~image-20190424141427790

    API 通用集成

    我们鼓励也支持将Pocsuite3作为安全产品中的一部分。只需要将Pocsuite3作为模块导入到你的项目中就能轻松使用。后面我们也会详细说明Pocsuite3是如何做到这一点的。

    pocsuite3.api将Pocsuite中所有接口暴露出来,不管是写PoC还是集成到自己的环境,只需要使用这就可以。一个简单调用Demo。

     

    最后

    一个功能完备的框架并不只是一个可以批量处理任务的引擎,很多东西需要在实战中积累并以最好的方式实现出来(俗称踩坑)。在打造自己的PoC框架过程中,一定要清楚自己需要的是什么,以及用何种方式将它优雅的解决?下篇将具体谈谈Pocsuite3中的框架结构。


    Paper

    本文由 Seebug Paper 发布,如需转载请注明来源。本文地址:https://paper.seebug.org/904/

    作者:吴烦恼 | Categories:安全研究技术分享 | Tags:
  • 【ZoomEye专题报告】DDoS 反射放大攻击全球探测分析

    2019-04-24

    作者:知道创宇404实验室
    ZoomEye专题:https://www.zoomeye.org/topic?id=Global-Detection-and-Analysis-of-Amplified-Reflection-DDoS-Attacks
    PDF 版本:下载
    English Version: https://paper.seebug.org/899/

    1.更新情况

    版本 时间 描述
    第一版 2017/08/07 完成第一轮数据统计,输出报告,完善文档格式
    第二版 2017/08/14 完成第二轮数据统计,输出报告,完善文档格式
    第三版 2017/11/15 完成第三轮数据统计,在第二轮的基础上增加对cldap的探测
    第四版 2018/03/05 完成第四轮数据统计,在第三轮的基础上增加对Memcached的探测

    2.概述

    DDos攻击是一种耗尽资源的网络攻击方式,攻击者通过大流量攻击,有针对性的漏洞攻击等耗尽目标主机的资源来达到拒绝服务的目的。

    反射放大攻击是一种具有巨大攻击力的DDoS攻击方式。攻击者只需要付出少量的代价,即可对需要攻击的目标产生巨大的流量,对网络带宽资源(网络层)、连接资源(传输层)和计算机资源(应用层)造成巨大的压力,2016年10月美国Dyn公司的DNS服务器遭受DDoS攻击,导致美国大范围断网。事后的攻击流量分析显示,DNS反射放大攻击与SYN洪水攻击是作为本次造成美国断网的拒绝服务攻击的主力。由于反射放大攻击危害大,成本低,溯源难,被黑色产业从业者所喜爱。

    在2017年8月3日到2017年8月6日期间ZoomEye网络空间探测引擎对全网进行第一轮的探测,统计可被利用进行DDoS反射放大攻击的主机数,发布了《DDoS反射放大攻击全球探测分析-第一版》,之后在2017年8月11日到2017年8月13日期间ZoomEye网络空间探测引擎再次对全网进行了探测,发布了《DDoS反射放大攻击全球探测分析-第二版》。之后在2017年11月13日到2017年11月15日期间,ZoomEye网络空间探测引擎探测到了另一个活动频繁的攻击——CLDAP DDoS反射放大攻击,随后对DDoS反射放大攻击进行了第三轮的探测,发布了《DDoS反射放大攻击全球探测分析-第三版》。

    随后在2018年3月1日,ZoomEye又探测到在网络空间中频繁活动Memcached DRDoS, 进行第四轮对DDoS反射放大攻击的探测。

    3.第四轮放大攻击数据分析

    [注:下面数据统计均基于第四轮 2018/03/05]

    第四轮探测,ZoomEye网络空间探测引擎在对前面两轮6种DDoS攻击的探测的基础上,增加了对Memcached攻击的探测。

    3.1.CHARGEN

    通过ZoomEye网络空间探测引擎获取到9万(95,010)台主机开放了19端口。然后对这9万主机进行放大倍率的探测,实际上只有1万(10,122)台主机开启了19点端口,占总数的10.65%。在开启了19端口的主机中,有6千(6,485)台主机的放大倍数能够达到10倍以上,占总数的64.07%,剩下的主机的放大倍数主要集中在2倍。相关数据如图3.1-1所示:

    对放大倍数达到10以上的主机流量进行统计,我们总共发送了870KB(891,693 byte)的请求流量,得到了71M(74,497,401 byte)响应流量,产生了83倍的放大流量。假设一台主机1分钟内可以成功响应100个请求数据包,计算得到攻击流量有947Mbits/s。本轮探测对最大放大倍数进行了统计,得到了Chargen协议单次请求响应最高能放大319倍流量。

    上面的数据和之前两次的的数据进行比较,Chargen DDoS攻击的危害并没有减小,反而有增大的趋势。

    根据ZoomEye网络空间探测引擎的探测结果,对可利用的Chargen主机进行全球分布统计,见图3.1-2:

    3.1-2 Chargen协议19端口可利用主机全球分布图从图中可以看出仍然是韩国具有最多数量的可被利用进行DDos反射放大攻击的主机,我国排在第二 。下面,对我国各省份的情况进行统计,如图3.1-3所示:

    3-1.3 Chargen协议19端口可利用主机全国分布图

    3.2.NTP

    通过ZoomEye网络空间探测引擎获取到14万(147,526)台开启了UDP 123端口的主机。利用这些数据进行放大倍率探测,实际上只有1千(1,723)台主机开启了UDP 123端口,占总数的1.17%,放大倍数大于10的主机只有4台,占有响应主机总数的0.23%,具体数量见图3.2-1所示:

    和上一次探测的结果相比,利用NTP进行反射DDoS攻击的隐患基本消除,不管是NTP服务器的总量还是可被利用服务器数量,都大幅度下降,尤其是本次探测中,只发现4台可被利用的NTP服务器,而且这4台皆位于日本。我国未被探测到可被利用的NTP服务器。

    3.3.DNS

    通过Zoomeye网络空间探测引擎获取到2千万(21,261,177)台UDP 53端口相关的主机,对这些主机进行放大倍率探测,实际上只有384万(3,847,687)台主机开启了53端口,占了扫描总数的18.1%。在开启了53端口的主机中,有3万(31,999)台主机放大倍数在10倍以上,只占总数的0.83%,而放大倍数为1的主机有277万(2,776,027)台,具体数据见图3.3-1:

    和上一版的数据相比,互联网上DNS服务器的和可被利用的DNS服务器数量均处于下降状态。

    下面,再来看看这3万台放大倍数大于10的主机全球分布情况,如图3.3-2所示,可以看到,和上一轮相比,数量排名没啥变化,仍然是美国排在第一位。我们又对可利用主机在我国的分布情况进行了统计,如图3.3-3所示,和上一轮相比,湖北省的DNS服务器数量有了明显的提高。

    3.3-2 DNS协议53端口可利用主机全球分布图

    3.3-3 DNS协议53端口可利用主机全国分布图

    3.4.SNMP

    通过Zoomeye网络空间探测引擎获取到1千万(11,681,422)台UDP 161端口相关的主机,对这些主机进行放大倍率探测,实际上有167万(1,677,616)台主机开启了161端口,占了扫描总数的14.36%。在开启了161端口的主机中,有61万(617,980)台主机放大倍数在10倍以上,占了总数的36.84%,具体数据见图3.4-1:

    本次探测得到的数据和前一轮的数据相比较,探测到的SNMP主机数增加,而可利用的主机数却呈下降状态。

    下面,再来看看这61万台放大倍数大于10的主机全球分布情况,如图3.4-2所示,可以看到,我国的主机量上升到了第二位。我们又对可利用主机在我国的分布情况进行了统计,如图3.4-3所示,台湾,北京,黑龙江仍然是受影响最深的几个省份之一。

    3.4-2 SNMP协议161端口可利用主机全球分布图

    3.4-3 SNMP协议161端口可利用主机全国分布图

    3.5.SSDP

    通过Zoomeye网络空间探测引擎获取到3千万(32,522,480)台UDP 1900端口相关的主机,对这些主机进行放大倍率探测,实际上有60万(609,014)台主机开启了1900端口,占了扫描总数的1.87%。在开启了1900端口的主机中,有57万(572,936)台主机放大倍数在10倍以上,占了总数的94.08%,具体数据见图3.5-1:

    下面,再来看看这57万台放大倍数大于10的主机全球分布情况,如图3.5-2所示,和上一轮探测的数据相比,没有明显的变化。 再对我国的数据进行统计,如图3.5-3所示,台湾仍是我国可被利用的主机数最多的省份,远远超过我国的其他省份。

    3.5-2 SSDP协议1900端口可利用主机全球分布图

    3.5-3 SSDP协议1900端口可利用主机全国分布图

    3.6.CLDAP

    通过Zoomeye网络空间探测引擎获取到40万(403,855)台UDP 389端口相关的主机,对这些主机进行放大倍率探测,实际上有1万(17,725)台主机开启了389端口,占了扫描总数的4.39%。在开启了389端口的主机中,有1万(17,645)台主机放大倍数在10倍以上,占了总数的99.55%,具体数据见图3.6-1:

    下面,再来看看这2万台放大倍数大于10的主机全球分布情况,如图3.5-2所示,可以看到,美国仍然是可被利用的CLDAP服务器数量最多的国家,我国依旧排第三位。我们又对可利用主机在我国的分布情况进行了统计,如图3.5-3所示,台湾依然是我国可被利用的主机数最多的省份,和香港一起远远超过我国的其他省份地区。

    3.6-2 LDAP协议389端口可利用主机全球分布图

    3.6-3 LDAP协议389端口可利用主机全国分布图

    3.7.Memcached

    Memcached是一个自由开源的,高性能,分布式内存对象缓存系统。Memcached是以LiveJournal旗下Danga Interactive公司的Brad Fitzpatric为首开发的一款软件。现在已成为mixi、hatena、Facebook、Vox、LiveJournal等众多服务中提高Web应用扩展性的重要因素。Memcached是一种基于内存的key-value存储,用来存储小块的任意数据(字符串、对象)。这些数据可以是数据库调用、API调用或者是页面渲染的结果。Memcached简洁而强大。它的简洁设计便于快速开发,减轻开发难度,解决了大数据量缓存的很多问题。它的API兼容大部分流行的开发语言。本质上,它是一个简洁的key-value存储系统。一般的使用目的是,通过缓存数据库查询结果,减少数据库访问次数,以提高动态Web应用的速度、提高可扩展性。

    Memcached Server在默认情况下同时开启了TCP/UDP 11211端口,并且无需认证既可使用Memcached的储存服务。2018年3月2日,ZoomEye对全网开启了UDP 11211端口,并且无需认证的Memcached进行探测,共得到14142个目标,并对这些目标进行全球分布统计,如图3.7-1所示:

    3.7-1 Memcached可被利用主机全球分布图从上图中可以明显的看出我国对安全问题的重视程度和国外仍然有较大的差距。在14142个有效目标中,有11368个目标的IP地址位于我国。下面再对我国的目标进行全国分布统计,如图3.7-2所示:

    3.7-2 Memcached可被利用主机全国分布图Memcached未开启认证的情况下,任何人都可以访问Memcached服务器,储存键值对,然后可以通过key来获取value。所以,为了摸清出全球Memcache可利用的情况,我们在Memcached储存一个key为1byte的,value为1kb的数据,然后我们再通过该key获取到value,这样就产生了将近1000倍的放大效果。Memcached在默认情况下还会开启UDP端口,所以这就导致了Memcached可以被利用来进行DDoS放射放大攻击。而Memcached能放大多少倍取决于:

    1. Memcached服务器带宽
    2. Memcached能储存的值的最大长度

    利用自己的服务器进行一个测试,首先让能利用的Memcached储存一个1kb长度的值,然后同时向所有目标获取值,能收到886Mbit/s的流量,如图3.7-3所示:

    3.7-3 流量统计图

    4.总结

    和前面三轮探测的数据相比,在第四轮的探测中,变化最大的是NTP服务,当前互联网的NTP服务器已经没办法造成大流量的DDoS反射放大攻击了。与之相比,其他协议也或多或少的降低了可被利用的主机数量 。DDoS反射放大攻击仍然危害巨大,DDoS防御仍然刻不容缓。 从这次ZoomEye探测到的数据中,再和公网上的Memcached服务进行对比:

    4-4 ZoomEye探测11211端口数量在ZoomEye的数据库中,开启11211端口的目标有54万,其中美国有23万,中国有13万的目标,但是开启了UDP 11211端口的数据中,总量只有14142,其中美国有1070的目标,中国有11368个目标主机。

    从这些数据对比中,可以看出美国对此类的安全事件有非常快的响应速度,中国和美国的差距还很大。

    从放大效果来看,虽然可利用的目标已经缩减到1万的量级,但是仍然能造成大流量的DDos攻击。

    对于Memcached的用户,我们建议关闭其UDP端口,并且启用SASL 认证,对于运营商,建议在路由器上增加的uRPF(Unicast Reverse Path Forwarding)机制,该机制是一种单播反向路由查找技术,用于防止基于源地址欺骗的网络攻击行为,利用该机制能使得UDP反射攻击失效。

    5.参考链接

    1.Stupidly Simple DDoS Protocol (SSDP) generates 100 Gbps DDoS.
    https://blog.cloudflare.com/ssdp-100gbps/
    2.基于SNMP的反射攻击的理论及其实现.
    http://drops.xmd5.com/static/drops/tips-2106.html
    3.基于Memcached分布式系统DRDoS拒绝服务攻击技术研究.
    https://paper.seebug.org/535/
    4.ZoomEye Chargen dork.
    https://www.zoomeye.org/searchResult?q=port%3A19
    5.ZoomEye NTP dork.
    https://www.zoomeye.org/searchResult?q=port%3A123
    6.ZoomEye DNS dork.
    https://www.zoomeye.org/searchResult?q=port%3A53
    7.ZoomEye SNMP dork.
    https://www.zoomeye.org/searchResult?q=port%3A161
    8.ZoomEye LDAP dork.
    https://www.zoomeye.org/searchResult?q=port%3A389
    9.ZoomEye SSDP dork.
    https://www.zoomeye.org/searchResult?q=port%3A1900
    10.ZoomEye Memcached dork.
    https://www.zoomeye.org/searchResult?q=port%3A11211

     

    Paper

    本文由 Seebug Paper 发布,如需转载请注明来源。本文地址:https://paper.seebug.org/898/

    作者:吴烦恼 | Categories:安全研究 | Tags:
  • Drupal 1-click to RCE 分析

    2019-04-22

    作者:LoRexxar'@知道创宇404实验室
    时间:2019年4月19日

    2019年4月11日,zdi博客公开了一篇A SERIES OF UNFORTUNATE IMAGES: DRUPAL 1-CLICK TO RCE EXPLOIT CHAIN DETAILED.

    整个漏洞的各个部分没什么特别的,巧妙的是,攻击者使用了3个漏洞+几个小trick,把所有的漏洞链接起来却成了一个还不错的利用链,现在我们就来一起看看整个漏洞.

    无后缀文件写入

    在Drupal的机制中,设定了这样一条规则。

    用户上传的图片文件名将会被保留,如果出现文件名相同的情况,那么文件名后面就会被跟上_0,_1依次递增。

    在Drupal中为了兼容各种编码,在处理上传文件名时,Drupal会对文件名对相应的处理,如果出现值小于0x20的字符,那么就会将其转化为_

    但如果文件名中,如果出现了\x80\xff的字符时,PHP就会抛出PREG_BAD_UTF8_ERROR,如果发生错误,那么preg_replace就会返回NULL,$basename就会被置为NULL。

    当basename为空时,后面的文件内容会被写入到形似_0的文件内

    在这个基础下,原本会被上传到

    则会被写入

    当服务端开启了评论头像上传,或者是拥有作者账号时

    攻击者可以通过上传一张恶意构造的gif图,然后再上传一张带有恶意字符的同一张图,那么就会将恶意图片的内容写入到相应目录的_0

    但如果我们直接访问这个文件时,该文件可能不会解析,这是因为

    1. 浏览器首先会根据服务端给出的content-type解析页面,而服务端一般不会给空后缀的文件设置content-type,或者设置为application/octet-stream
    2. 其次浏览器会根据文件内容做简单的判断,如果文件的开头为<html>,则部分浏览器会将其解析为html
    3. 部分浏览器还可能会设置默认的content-type,但大部分浏览器会选择不解析该文件。

    这时候我们就需要一个很特殊的小trick了,a标签可以设置打开文件的type(only not for chrome)

    当你访问该页面时,页面会被解析为html并执行相应的代码。

     

     

    当被攻击者访问该页面时,我们就可以执行任意的xss,这为后续的利用带来了很大的便利,我们有了一个同源环境下的任意js执行点,让我们继续看。

    phar反序列化RCE

    2018年BlackHat大会上的Sam Thomas分享的File Operation Induced Unserialization via the “phar://” Stream Wrapper议题,原文https://i.blackhat.com/us-18/Thu-August-9/us-18-Thomas-Its-A-PHP-Unserialization-Vulnerability-Jim-But-Not-As-We-Know-It-wp.pdf 

    在该议题中提到,在PHP中存在一个叫做Stream API,通过注册拓展可以注册相应的伪协议,而phar这个拓展就注册了phar://这个stream wrapper。

    在我们知道创宇404实验室安全研究员seaii曾经的研究(https://paper.seebug.org/680/)中表示,所有的文件函数都支持stream wrapper。

    也就是说,如果我们找到可控的文件操作函数,其参数可控为phar文件,那么我们就可以通过反序列化执行js。

    在Drupal中,存在file system功能,其中就有一个功能,会把传入的地址做一次is_dir的判断,这里就存在这个问题

    直接使用下面的payload生成文件

     

     

    修改后缀为png之后,传图片到服务端,并在file system中设置

    即可触发

    漏洞要求

    这个漏洞在Drual8.6.6的更新中被修复,所以漏洞要求为

    • <= Durpal 8.6.6
    • 服务端开启评论配图或者攻击者拥有author以上权限的账号
    • 被攻击者需要访问攻击者的url

    当上面三点同时成立时,这个攻击链就可以被成立

    漏洞补丁

    无后缀文件写入 SA-CORE-2019-004

    https://www.drupal.org/SA-CORE-2019-004

    如果出现该错误直接抛出,不继续写入

    https://github.com/drupal/drupal/commit/82307e02cf974d48335e723c93dfe343894e1a61#diff-5c54acb01b2253384cfbebdc696a60e7

    phar反序列化 SA-CORE-2019-002

    https://www.drupal.org/SA-CORE-2019-002

    写在最后

    回顾整个漏洞,不难发现其实整个漏洞都是由很多个不起眼的小漏洞构成的,Drupal的反序列化POP链已经被公开许久,phar漏洞也已经爆出一年,在2019年初,Drupal也更新修复了这个点,而preg_replace报错会抛出错误我相信也不是特别的特性,把这三个漏洞配合上一个很特别的a标签设置content-type的trick,就成了一个很漂亮的漏洞链。


    Paper

    本文由 Seebug Paper 发布,如需转载请注明来源。本文地址:https://paper.seebug.org/897/

    作者:吴烦恼 | Categories:安全研究技术分享 | Tags:
  • Apache 提权漏洞(CVE-2019-0211)复现

    2019-04-12

    作者:Hcamael@知道创宇404实验室
    时间:2019年4月12日

    本月Apache被公布了一个提权的漏洞,并且前天在GitHub上公布出了利用脚本,这几天我负责漏洞应急这个漏洞。

    本篇文章没有叫:《Apache 提权漏洞分析》是因为我觉得CARPE (DIEM): CVE-2019-0211 Apache Root Privilege Escalation这篇文章的分析写的挺好的,所以我没必要再翻译一遍了,本篇文章主要叙述复现该漏洞的过程中踩过的坑。

    复现环境

    我使用的复现环境是:

    1. apache使用apt安装的版本属于已经修复的版本,所以需要指定一下版本: # apt install apache2=2.4.29-1ubuntu4 apache2-bin=2.4.29-1ubuntu4 apache2-utils=2.4.29-1ubuntu4 apache2-data=2.4.29-1ubuntu4
    2. php直接用apt安装就好了
    3. exp地址: https://github.com/cfreal/exploits/blob/master/CVE-2019-0211-apache/cfreal-carpediem.php
    4. 需要开启ssl模块:a2enmod ssl

    关于需要开始ssl模块说明:

    1. 就算不开ssl模块,漏洞也是存在的
    2. 就算不开启ssl模块,你自己修改apache配置,能开启其他端口,也是能利用的
    3. 如果只开了80端口,则需要另行找一条利用链,github上公布exp在只开启了一个端口的情况下是无效的
    4. @cfreal的文章中已经说了,我这里在多说句,相关代码可以看看12还有SAFE_ACCPET的宏定义:

    简单的来说,只有在apache开启多个端口的情况下,才会生成mutex互斥锁,而在github上公布的exp就是通过apache的mutex对象来进行利用的。

    跑exp中遇到的一些坑

    我试过了很多版本,没有一个版本是能直接使用Github上的exp的,在上述表面的版本中,经过调试研究发现了两个问题导致了利用失败:

    1. $all_buckets = $i - 0x10 计算出问题
    2. $bucket_index = $bucket_index_middle - (int) ($total_nb_buckets / 2); 计算出问题

    第一个计算all_buckets的地址,使用gdb进行调试,你会发现,这个值并没有算错,但是在执行apache2ctl graceful命令以后,all_buckets 生成了一个新的值,不过只和之前的all_buckets地址差0x38000,所以这个问题很好解决:

    第二个计算没必要这么复杂,而且在我测试的版本中还是算的错误的地址,直接改成:

    ubuntu中的一个坑

    我的payload是:curl "http://localhost/cfreal-carpediem.php?cmd=id>/tmp/2323232"

    表面上看是执行成功了,但是却并没有在/tmp目录下发现2323232文件,经过随后的研究发现,systemd重定向了apache的tmp目录,执行下$find /tmp -name "2323232"就找到文件了,不过只有root用户能访问。如果不想让systemd重定向tmp目录也简单:

    这项为false就好了,PrivateTmp=false,改完以后重启一下,再测试一遍就能在tmp目录下写文件了

    关于成功率的说法

    在exp的注释中看到了说该利用没法100%成功,有失败的概率,所以我写了个脚本进行测试:

    我测试的跑了20次的结果:

    并没有遇到失败的情况

    总结

    其他版本的还没有进行测试,但是在这里给一些建议。

    1. check all_buckets地址

      这个挺简单的,执行完exp以后,有输出对应的pid和all_buckets地址,可以使用gdb attach上去检查下该地址是否正确:p all_buckets

      PS:这里要注意下,需要安装dbg包,才有all_buckets符号 :apt install apache2-dbg=2.4.29-1ubuntu4

      如果有问题,就调试检查exp中搜索all_buckets地址的流程

      如果没问题,就使用gdb attach主进程(root权限的那个进程),然后断点下在make_child,然后执行apache2ctl graceful,执行完然后在gdb的流程跳到make_child函数的时候,再输出一次:p all_buckets,和exp获取的值对比一下,如果一样就没问题了

    2. check my_bucket地址

      前面的流程和上面一样,重点关注在make_child函数中的my_bucket赋值的代码:3

      这里注意下,因为上面有一个fork,所以在gdb里还要加一句:set follow-fork-mode child

      my_bucket的值是一个指针,指向堆喷的地址,如果my_bucket的值没问题,exp基本就没问题了,如果不对,就调整$bucket_index

    更新

    debian 9测试成功:

    参考

    1. https://github.com/apache/httpd/blob/23167945c17d5764820fdefdcab69295745a15a1/server/mpm/prefork/prefork.c#L433
    2. https://github.com/apache/httpd/blob/23167945c17d5764820fdefdcab69295745a15a1/server/mpm/prefork/prefork.c#L1223
    3. https://github.com/apache/httpd/blob/23167945c17d5764820fdefdcab69295745a15a1/server/mpm/prefork/prefork.c#L691

    Paper

    本文由 Seebug Paper 发布,如需转载请注明来源。本文地址:https://paper.seebug.org/889/

    作者:吴烦恼 | Categories:安全研究 | Tags:
  • Confluence 未授权 RCE (CVE-2019-3396) 漏洞分析

    2019-04-09

    作者:Badcode@知道创宇404实验室
    时间:2019年4月8日

    看到官方发布了预警,于是开始了漏洞应急。漏洞描述中指出Confluence Server与Confluence Data Center中的Widget Connector存在服务端模板注入漏洞,攻击者能利用此漏洞能够实现目录穿越与远程代码执行。

    确认漏洞点是Widget Connector,下载最新版的比对补丁,发现在com\atlassian\confluence\extra\widgetconnector\WidgetMacro.java里面多了一个过滤,这个应该就是这个漏洞最关键的地方。

    可以看到

    TEMPLATE_PARAM的值就是_template,所以这个补丁就是过滤了外部传入的_template参数。

    翻了一下Widget Connector里面的文件,发现TEMPLATE_PARAM就是模板文件的路径。

    加载外部的链接时,会调用相对的模板去渲染,如上,模板的路径一般是写死的,但是也有例外,补丁的作用也说明有人突破了限制,调用了意料之外的模板,从而造成了模板注入。

    在了解了补丁和有了一些大概的猜测之后,开始尝试。

    首先先找到这个功能,翻了一下官方的文档,找到了这个功能,可以在文档中嵌入一些视频,文档之类的。

    看到这个,有点激动了,因为在翻补丁的过程中,发现了几个参数,urlwidthheight正好对应着这里,那_template是不是也从这里传递进去的?

    随便找个Youtube视频插入试试,点击预览,抓包。

    params中尝试插入_template参数,好吧,没啥反应。。

    开始debug模式,因为测试插入的是Youtube视频,所以调用的是com/atlassian/confluence/extra/widgetconnector/video/YoutubeRenderer.class

     

     

     

    getEmbeddedHtml下断点,先会调用getEmbedUrl对用户传入的url进行正则匹配,因为我们传入的是个正常的Youtube视频,所以这里是没有问题的,然后调用setDefaultParam函数对传入的其他参数进行处理。

    取出widthheight来判断是否为空,为空则设置默认值。关键的_template参数来了,如果外部传入的参数没有_template,则设置默认的Youtube模板。如果传入了,就使用传入的,也就是说,aaaa是成功的传进来了。

    大概翻了一下Widget Connector里面的Renderer,大部分是不能设置_template的,是直接写死了,也有一些例外,如Youtube,Viddler,DailyMotion等,是可以从外部传入_template的。

    能传递_template了,接下来看下是如何取模板和渲染模板的。

    跟进this.velocityRenderService.render,也就是com/atlassian/confluence/extra/widgetconnector/services/DefaultVelocityRenderService.class里面的render方法。