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

    2016-12-23

    Author: p0wd3r (知道创宇404安全实验室)

    Date: 2016-12-21

    0x00 漏洞概述


    1.漏洞简介

    Joomla 于12月13日发布了3.6.5的升级公告,此次升级修复了三个安全漏洞,其中 CVE-2016-9838 被官方定为高危。根据官方的描述,这是一个权限提升漏洞,利用该漏洞攻击者可以更改已存在用户的用户信息,包括用户名、密码、邮箱和权限组 。经过分析测试,成功实现了水平用户权限突破,但没有实现垂直权限提升为管理员。

    2.漏洞影响

    触发漏洞前提条件:

    1. 网站开启注册功能
    2. 攻击者知道想要攻击的用户的 id (不是用户名)

    成功攻击后攻击者可以更改已存在用户的用户信息,包括用户名、密码、邮箱和权限组 。

    3.影响版本

    1.6.0 - 3.6.4

    0x01 漏洞复现


    1. 环境搭建

    docker-compose.yml:

    然后在 docker-compose.yml 所在目录执行docker-compose up,访问后台开启注册再配置SMTP即可。

    2.漏洞分析

    官方没有给出具体的分析,只给了描述:description

    翻译过来就是:

    对表单验证失败时存储到 session 中的未过滤数据的不正确使用会导致对现有用户帐户的修改,包括重置其用户名,密码和用户组分配。

    因为没有具体细节,所以我们先从补丁下手,其中这个文件的更改引起了我的注意:

    https://github.com/joomla/joomla-cms/commit/435a2226118a4e83ecaf33431ec05f39c640c744

    patch-1

    可以看到这里的$temp是 session 数据,而该文件又与用户相关,所以很有可能就是漏洞点。

    我们下面通过这样两个步骤来分析:

    1. 寻找输入点
    2. 梳理处理逻辑

    1.寻找输入点

    我们找一下这个 session 是从哪里来的:

    find-session

    components/com_users/controllers/registration.php中设置,在components/com_users/models/registration.php中获取。我们看components/com_users/controllers/registration.php中第108-204行的register函数:

    这两处设置 session 均在产生错误后进行,和漏洞描述相符,并且$requestData是我们原始的请求数据,并没有被过滤,所以基本可以把这里当作我们的输入点。

    我们来验证一下,首先随便注册一个用户,然后再注册同样的用户并开启动态调试:save-session

    由于这个用户之前注册过,所以验证出错,从而将请求数据写入了 session 中。

    取 session 的地方在components/com_users/models/registration.phpgetData函数,该函数在访问注册页面时就会被调用一次,我们在这时就可以看到 session 的值:session-value

    由于存储的是请求数据,所以我们还可以通过构造请求来向 session 中写入一些额外的变量。

    2.梳理处理逻辑

    输入点找到了,下面来看我们输入的数据在哪里被用到。我们看components/com_users/models/registration.phpregister函数:

    在这里调用了之前的getData函数,然后使用请求数据对$data赋值,再用$data对用户数据做更改。

    首先跟进$user->bind($data),在libraries/joomla/user/user.php中第595-693行:

    这里根据我们传入的数据对对象的属性进行赋值,setProperties并没有对赋值进行限制。

    接下来我们看$user->save($data),在libraries/joomla/user/user.php中第706-818行:

    具体内容就是将$user的属性绑定到$table中,然后对$table进行检查,这里仅仅是过滤特殊符号和重复的用户名和邮箱,如果检查通过,将数据存入到数据库中,存储数据的函数在libraries/joomla/table/user.php中:

    如果主键存在则更新,主键不存在则插入。

    整个的流程看下来我发现这样一个问题:

    如果$data中有id这个属性并且其值是一个已存在的用户的 id ,由于在bindsave中并没有对这个属性进行过滤,那么最终保存的数据就会带有 id 这个主键,从而变成了更新操作,也就是用我们请求的数据更新了一个已存在的用户。

    实际操作一下,我们之前注册了一个名字为 victim 的用户,数据库中的 id 是57:

    initial-id

    然后我们以相同的用户名再发起一次请求,然后截包,添加一个值为57名为jform[id]的属性:add-id

    放行后由于重复注册从而发生错误,程序随后将请求数据记录到了 session 中:

    session-id

    接下来我们发送一个新的注册请求,用户名邮箱均为之前未注册过的,在save函数处下断点:user-id

    id 被写进了$user中。然后放行请求,即可在数据库中看到结果:change-user

    之前的 victim 已被新用户 attacker 取代。

    整个攻击流程总结如下:

    1. 注册用户A
    2. 重复注册用户A,请求包中加上想要攻击的用户C的 id
    3. 注册用户B
    4. 用户B替代了用户C

    (上面的演示中A和C是同一个用户)

    需要注意的是我们不能直接发送一个带有 id 的请求来更新用户,这样的请求会在validate函数中被过滤掉,在components/com_users/controllers/registration.phpregister函数中:

    所以我们采用的是先通过validate触发错误来将 id 写到 session 中,然后发送正常请求,在register中读取 session 来引入 id,这样就可以绕过validate了。

    另外一点,实施攻击后被攻击用户的权限会被改为新注册用户的权限(一般是 Registered),这个权限目前我们无法更改,因为在getData函数中对groups做了强制赋值:

     

    所以目前只是实现了水平权限的提升,至于是否可以垂直权限提升以及怎么提升还要等官方的说明或者是大家的分析。

    由于没有技术细节,一切都是根据自己的推断而来,如有错误,还望指正 🙂

    3.补丁分析

    patch-2

    使用 session 时仅允许使用指定的属性。

    0x02 修复方案


    升级至3.6.5

    https://www.joomla.org/announcements/release-news/5693-joomla-3-6-5-released.html

    0x03 参考


     

     

    作者:kk | Categories:技术分享 | Tags:
  • NTPD拒绝服务漏洞(CVE-2016-7434) 分析

    2016-12-23

    Author: LG, dawu (知道创宇404实验室)

    前言


    NTP服务对于互联网来说是不可或缺的,很多东西都能和它联系到一起。就在不久前,轰动一时的德国断网事件中也出现了它的影子。保证NTP服务器的安全是很重要的!

    0x00 漏洞概述


    1.漏洞简介

    NTPD是一个linux系统下同步不同机器时间的服务程序。
    近日NTP.org公布了一个拒绝服务漏洞,该漏洞能够导致NTPD服务遭受远程DoS攻击。

    2.漏洞影响

    受影响版本面临DoS攻击风险

    3.影响版本

    • 4.3.90
    • 4.3.25
    • 4.3
    • 4.3.93
    • 4.3.92
    • 4.3.77
    • 4.3.70
    • 4.2.8p8
    • 4.2.8p7
    • 4.2.8p6
    • 4.2.8p5
    • 4.2.8p4
    • 4.2.8p3
    • 4.2.8p2
    • 4.2.8p1
    • 4.2.7p22

    0x01 漏洞详情


    1.漏洞细节

    NTPD服务端配置安全性低,能接收任意端mrulist数据包。此时攻击者能够远程发送经过构造的mrulist数据包对其进行Dos攻击。

    2.漏洞检测方法

    使用以下命令检测NTP版本: # ntpq -c version 受影响版本列表中的版本未作相关安全配置将受漏洞影响。 github上已有公布的漏洞利用poc,但是该poc会使NTPD服务崩溃,利用后需要重启服务。
    漏洞利用poc

    3.漏洞复现

    docker搭建环境:

    ntpd1

    之后命令行输入:

    最后NTPD服务崩溃

    --1

    --2

    4.漏洞分析

    4.1 payload分析

    漏洞发现者构造了这样一段mrulist数据包

    base64解码后

    base64

    base64解码(以16进制显示):

    此处参考NTP协议格式:

    NTP packet = NTP header + Four TimeStamps = 48byte

    NTP header : 16byte

    LI(LeapYearIndicator) VN(VersionNumber) Mode Stratum Poll(PollInterval) Precision
    2bit 3bit 3bit 8bit 8bit 8bit

    详情请看 NTP报文格式

    主要字段的解释如下: ·LI(Leap Indicator,闰秒提示):长度为2比特,值为“11”时表示告警状态,时钟未被同步。为其他值时NTP本身不做处理。 ·VN(Version Number,版本号):长度为3比特,表示NTP的版本号,目前的最新版本为4。 ·Mode:长度为3比特,表示NTP的工作模式。不同的值所表示的含义分别是:0未定义、1表示主动对等体模式、2表示被动对等体模式、3表示客户模式、4表示服务器模式、5表示广播模式或组播模式、6表示此报文为NTP控制报文、7预留给内部使用。 ·Stratum:系统时钟的层数,取值范围为1~16,它定义了时钟的准确度。层数为1的时钟准确度最高,准确度从1到16依次递减,层数为16的时钟处于未同步状态。 ·Poll:轮询时间,即两个连续NTP报文之间的时间间隔。 ·Precision:系统时钟的精度。

    了解了NTP的报文格式后,上文数据包中的NTP header:

    payload分析到这里暂时无下文,于是我们转去研究了漏洞触发点部分

    4.2漏洞触发点分析

    如下图,我们根据valgrind给出的调试信息寻找漏洞触发点

    ----

    判断漏洞触发点位于ntpd/ntpcontrol.c:4041,readmru_list()函数体内

    ----1

    漏洞触发原因是estrdup函数空指针的引用。

    estrdup函数的参数不能为NULL,否则会使程序崩溃。因为estrdup函数包含了strdup函数,而strdup函数又包含了strlen函数,该函数参数不能是NULL

    那么这说明val是有可能引入空指针的了? val是由ctl_getitem()函数引入的,稍后我们上溯去看。

    我们先来看readmrulist函数中var list

    它把mrulist数据包中各字段输入in_parms中,并且用到了sizeof()

    看到这里,我们明白了nonce_text字段长度是6字节。

    接着我们上溯ctl_getitem函数。它的功能是处理解码后数据包中的数据。首先处理的就是nonce_text字段。ctl1

    这里val就是*data,*var_list就是in_parms,v就是每个字段的数据

    ctl3

    注意line(3103-3107)以及line(3111-3116)处的代码: while循环的条件是从字符串首部开始扫描,出现空或者,就把reqpt右移一个字节。
    for循环的判断语句中以,为终止标志,以=为赋值标志。如果没有出现=来进行判断后赋值,字段就会一直为空。
    关键点出现了:在之前构造payload时,目标就是这里(阻止=的出现)。

    4.3payload构造分析

    我们延续对payload的分析,结合上文payload分析base64解码部分信息,其实已经显示出来了。6nonce,大家注意到了吗? nonce前面的一个字节正常格式原本应该是=的,漏洞发现者把它置为6了(16进制就是\x36)。其实只要构造"nonce"前一个字节不是=(16进制是\x3d)而且前3个字节都为NULL,漏洞触发条件就满足了。

    我们来验证一下:

    --1-1

    --2-1

    到此总结一下: payload构造关键点在于上文中NTP header格式如下
    NULL NULL NULL 非= nonce,

    ps:非=需要的是能正常解码出来的字符串,乱码是不行的。

    5.补丁分析

    ntp4.2.8p9版本修补了这个漏洞。官方修补方案是在read_mru_list()中严格地进行val参数的检测并做了一些限制措施。此外官方在最新版ntp_control.c的release中又对ctl_getitem函数进行了安全修改。

    GitLab代码补丁对比链接

    1

    2

    我们分析后认为补丁关键点如下:

    其中char * val 变为const char * val

    修改后逻辑运行为必须通过void * 从指针中去掉const属性。 接着严格判断val是不是NULL,若val指针为NULL则中断。 在此情况下原漏洞触发点处变为先判断*val,判断式只会为真,避免了空指针的引用,从而修复了此处漏洞。

    6.漏洞利用分析

    在实际场景中,存在漏洞的NTPD服务器如果未作任何防护措施,攻击者极易对其进行远程DoS攻击。但是攻击结果仅是使服务崩溃,重启服务就能正常运行,对NTP服务器本身无其他深层影响。 但是,如实验室,飞机场,银行等机构的业务结算对于时间的校验应该非常严格。一旦针对性地攻击与它们相关联的NTP服务器导致系统时间无法正常同步,对于业务结算等是能够造成一定冲击的。

    0x02 漏洞防护措施


    1. 只允许接收来自信任主机的mrulist查询包
    2. 升级到ntpd4.2.8p9
    3. 执行BCP-38标准

    0x03 参考


     

    作者: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: