<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Rce on 诗与胡说</title>
    <link>https://kylingit.com/tags/rce/index.xml</link>
    <description>Recent content in Rce on 诗与胡说</description>
    <generator>Hugo -- gohugo.io</generator>
    <language>zh_cn</language>
    <copyright>Copyright © 2021 Kylinking</copyright>
    <atom:link href="https://kylingit.com/tags/rce/index.xml" rel="self" type="application/rss+xml" />
    
    <item>
      <title>Wordpress Image 远程代码执行漏洞分析</title>
      <link>https://kylingit.com/blog/wordpress-image-%E8%BF%9C%E7%A8%8B%E4%BB%A3%E7%A0%81%E6%89%A7%E8%A1%8C%E6%BC%8F%E6%B4%9E%E5%88%86%E6%9E%90/</link>
      <pubDate>Thu, 21 Feb 2019 14:45:49 +0000</pubDate>
      
      <guid>https://kylingit.com/blog/wordpress-image-%E8%BF%9C%E7%A8%8B%E4%BB%A3%E7%A0%81%E6%89%A7%E8%A1%8C%E6%BC%8F%E6%B4%9E%E5%88%86%E6%9E%90/</guid>
      <description>

&lt;script src=&#34;https://blog-1252261399.cos-website.ap-beijing.myqcloud.com/pangu.js&#34;&gt;&lt;/script&gt;

&lt;h3 id=&#34;0x01-概述&#34;&gt;0x01 概述&lt;/h3&gt;

&lt;p&gt;2月20日，RIPS披露了&lt;code&gt;Wordpress&lt;/code&gt;内核&lt;code&gt;Image&lt;/code&gt;模块相关的一个高危漏洞，该漏洞由目录穿越和文件包含组成，最终可导致远程代码执行，目前还没有PoC披露。&lt;/p&gt;

&lt;p&gt;从&lt;code&gt;RIPS&lt;/code&gt;描述的细节来看，漏洞出现在&lt;code&gt;wordpress&lt;/code&gt;编辑图片时，由于没有过滤&lt;code&gt;Post Meta&lt;/code&gt; 值导致可以修改数据库中&lt;code&gt;wp_postmeta&lt;/code&gt;表的任意字段，而在加载本地服务器上的文件时没有对路径进行过滤，导致可以传递目录穿越参数，最终保存图片时可以保存至任意目录。当某个主题include了某目录下的文件时，便可以造成代码执行。&lt;/p&gt;

&lt;h3 id=&#34;0x02-环境搭建&#34;&gt;0x02 环境搭建&lt;/h3&gt;

&lt;p&gt;该漏洞影响&lt;code&gt;4.9.9&lt;/code&gt;版本以下的&lt;code&gt;wordpress&lt;/code&gt;程序，&lt;code&gt;4.9.9&lt;/code&gt;引入了过滤函数，对用户输入的&lt;code&gt;post data&lt;/code&gt;进行了检查，不合法的参数被过滤，主要修改如下图：&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1252261399.cos-website.ap-beijing.myqcloud.com/images/20190221162810.png&#34; alt=&#34;&#34; /&gt;&lt;/p&gt;

&lt;p&gt;值得注意的是，在安装低版本时，安装过程中会自动更新核心文件，因此旧版本的&lt;code&gt;wp-admin/includes/post.php&lt;/code&gt;会更新至最新版本，所以安装过程中可以删除自动更新相关模块，或者离线安装。&lt;/p&gt;

&lt;h3 id=&#34;0x03-漏洞分析&#34;&gt;0x03 漏洞分析&lt;/h3&gt;

&lt;h4 id=&#34;漏洞一-数据覆盖&#34;&gt;漏洞一：数据覆盖&lt;/h4&gt;

&lt;p&gt;漏洞出现在wordpress媒体库裁剪图片的过程，当我们上传图片到媒体库时，图片会被保存至&lt;code&gt;wp-content/uploads/yyyy/mm&lt;/code&gt;目录，同时会在数据库中wp_postmeta表插入两个值，分别是&lt;code&gt;_wp_attached_file&lt;/code&gt;和&lt;code&gt;_wp_attachment_metadata&lt;/code&gt;，保存了图片位置和属性相关的序列化信息。&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1252261399.cos-website.ap-beijing.myqcloud.com/images/20190221164008.png&#34; alt=&#34;&#34; /&gt;&lt;/p&gt;

&lt;p&gt;当我们修改图片属性（例如修改标题或者说明）的时候，&lt;code&gt;admin-media-Edit more details&lt;/code&gt; 会调用&lt;code&gt;wp-admin/includes/post.php&lt;/code&gt;的&lt;code&gt;edit_post()&lt;/code&gt;方法，该方法的参数全部来自于&lt;code&gt;$_POST&lt;/code&gt;，没有进行过滤&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1252261399.cos-website.ap-beijing.myqcloud.com/images/20190221163553.png&#34; alt=&#34;&#34; /&gt;&lt;/p&gt;

&lt;p&gt;然后会调用到&lt;code&gt;update_post_meta()&lt;/code&gt;方法，该方法根据&lt;code&gt;$post_ID&lt;/code&gt;修改&lt;code&gt;post meta field&lt;/code&gt;，接着调用&lt;code&gt;update_metadata()&lt;/code&gt;更新&lt;code&gt;meta&lt;/code&gt;数据，完成之后更新&lt;code&gt;post&lt;/code&gt;数据，调用&lt;code&gt;wp_update_post()&lt;/code&gt;方法&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1252261399.cos-website.ap-beijing.myqcloud.com/images/20190221165642.png&#34; alt=&#34;&#34; /&gt;&lt;/p&gt;

&lt;p&gt;在&lt;code&gt;wp_update_post()&lt;/code&gt;方法中，如果&lt;code&gt;post_type=attachment&lt;/code&gt;，则进入&lt;code&gt;wp_insert_attachment()&lt;/code&gt;，接着调用&lt;code&gt;wp_insert_post()&lt;/code&gt;，在&lt;code&gt;wp_insert_post()&lt;/code&gt;方法中判断了&lt;code&gt;meta_input&lt;/code&gt;参数，如果传入了该参数，就遍历数组用来更新&lt;code&gt;post_meta&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1252261399.cos-website.ap-beijing.myqcloud.com/images/20190221172343.png&#34; alt=&#34;&#34; /&gt;&lt;/p&gt;

&lt;p&gt;进入&lt;code&gt;update_post_meta()&lt;/code&gt;，调用&lt;code&gt;update_metadata()&lt;/code&gt;，在&lt;code&gt;update_metadata()&lt;/code&gt;方法中对数据库进行更新操作，而在整个过程中对键值没有任何过滤，意味着我们可以传入指定的key来设置它的值，调用栈如下图所示&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1252261399.cos-website.ap-beijing.myqcloud.com/images/20190221165806.png&#34; alt=&#34;&#34; /&gt;&lt;/p&gt;

&lt;p&gt;于是构造数据包更新数据库中&lt;code&gt;_wp_attached_file&lt;/code&gt;的值，插入一个包含&lt;code&gt;../&lt;/code&gt;的值，以便在下面触发目录遍历。&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1252261399.cos-website.ap-beijing.myqcloud.com/images/20190221183004.png&#34; alt=&#34;&#34; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1252261399.cos-website.ap-beijing.myqcloud.com/images/20190221174154.png&#34; alt=&#34;&#34; /&gt;&lt;/p&gt;

&lt;p&gt;这是第一个漏洞——通过参数覆盖了数据库数据，在补丁处正是对&lt;code&gt;meta_input&lt;/code&gt;这个参数做了过滤，如果包含则通过对比&lt;code&gt;array&lt;/code&gt;舍弃该参数。&lt;/p&gt;

&lt;h4 id=&#34;漏洞二-目录遍历&#34;&gt;漏洞二：目录遍历&lt;/h4&gt;

&lt;p&gt;接着寻找一个获取&lt;code&gt;_wp_attached_file&lt;/code&gt;的值并进行了文件操作相关的方法。&lt;/p&gt;

&lt;p&gt;在&lt;code&gt;wordpress&lt;/code&gt;的&lt;code&gt;图片裁剪&lt;/code&gt;功能中，有这样的功能：&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;图片存在于&lt;code&gt;wp-content\uploads\yyyy\mm&lt;/code&gt;目录，则从该目录读取图片，修改尺寸后另存为一张图片；&lt;/li&gt;
&lt;li&gt;如果图片在该目录不存在，则通过&lt;strong&gt;本地&lt;/strong&gt;服务器下载该图片，如从&lt;code&gt;http://127.0.0.1/wordpress/wp-content/uploads/2019/02/admin.jpeg&lt;/code&gt;下载，裁剪后重新保存。&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;这个功能是为了方便一些插件动态加载图片时使用。&lt;/p&gt;

&lt;p&gt;然而因为本地读取和通过&lt;code&gt;url&lt;/code&gt;读取的差异性，导致可以构造一个带参数的&lt;code&gt;url&lt;/code&gt;，如&lt;code&gt;http://127.0.0.1/wordpress/wp-content/uploads/2019/02/admin.jpeg?1.png&lt;/code&gt;，在本地读取时会发现找不到&lt;code&gt;admin.jpeg?1.png&lt;/code&gt;，而远程获取时会忽略&lt;code&gt;?&lt;/code&gt;后面的参数部分，照样获取到&lt;code&gt;admin.jpeg&lt;/code&gt;，裁剪后保存。如果构造的url包含路径穿越，例如&lt;code&gt;http://127.0.0.1/wordpress/wp-content/uploads/2019/02/admin.jpeg?../../1/1.png&lt;/code&gt;，&lt;code&gt;wordpress&lt;/code&gt;将裁减后的图片保存至指定的文件夹，当图片包含恶意代码被引用时，就可能造成代码执行。&lt;/p&gt;

&lt;p&gt;图片裁剪功能在&lt;code&gt;wp_crop_image()&lt;/code&gt;方法中，但是该方法不能在页面中触发，需要手动更改相应的&lt;code&gt;action&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;首先在页面裁剪图片，并点击保存&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1252261399.cos-website.ap-beijing.myqcloud.com/images/20190221233754.png&#34; alt=&#34;&#34; /&gt;&lt;/p&gt;

&lt;p&gt;抓取数据包：&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;action=image-editor&amp;amp;_ajax_nonce=4c354c778b&amp;amp;postid=5&amp;amp;history=%5B%7B%22c%22%3A%7B%22x%22%3A0%2C%22y%22%3A5%2C%22w%22%3A347%2C%22h%22%3A335%7D%7D%5D&amp;amp;target=all&amp;amp;context=edit-attachment&amp;amp;do=save
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;code&gt;post body&lt;/code&gt;包含了相应的&lt;code&gt;action&lt;/code&gt;和&lt;code&gt;context&lt;/code&gt;，以及供还原文件的历史文件大小，此处需要修改&lt;code&gt;action&lt;/code&gt;为&lt;code&gt;crop-image&lt;/code&gt;以便触发&lt;code&gt;wp_crop_image()&lt;/code&gt;方法，相关调用如下&lt;/p&gt;

&lt;p&gt;在&lt;code&gt;wp-admin/admin-ajax.php&lt;/code&gt;定义了裁剪图片的操作&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1252261399.cos-website.ap-beijing.myqcloud.com/images/20190221180906.png&#34; alt=&#34;&#34; /&gt;&lt;/p&gt;

&lt;p&gt;判断了用户权限和&lt;code&gt;action&lt;/code&gt;名称后调用&lt;code&gt;do_action&lt;/code&gt;，最终在&lt;code&gt;apply_filters()&lt;/code&gt;中进入&lt;code&gt;wp_crop_image()&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1252261399.cos-website.ap-beijing.myqcloud.com/images/20190221181053.png&#34; alt=&#34;&#34; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1252261399.cos-website.ap-beijing.myqcloud.com/images/20190221181232.png&#34; alt=&#34;&#34; /&gt;&lt;/p&gt;

&lt;p&gt;进入&lt;code&gt;wp_ajax_crop_image()&lt;/code&gt;方法，在这个方法中进行了多项判断，全部符合才能进入裁剪图片方法，如下图注释所示&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1252261399.cos-website.ap-beijing.myqcloud.com/images/20190221181644.png&#34; alt=&#34;&#34; /&gt;&lt;/p&gt;

&lt;p&gt;首先计算&lt;code&gt;nonce&lt;/code&gt;和&lt;code&gt;expected&lt;/code&gt;值并对比，如果不一致就验证不通过，相关方法是&lt;code&gt;check_ajax_referer()&lt;/code&gt;&amp;ndash;&amp;gt;&lt;code&gt;wp_verify_nonce()&lt;/code&gt;。注意到传入&lt;code&gt;check_ajax_referer()&lt;/code&gt;的&lt;code&gt;$attachment_id&lt;/code&gt;参数，该参数取自&lt;code&gt;$_POST[&#39;id&#39;]&lt;/code&gt;，并参与后面的&lt;code&gt;expected&lt;/code&gt;计算，因此当我们直接更改&lt;code&gt;action=crop-image&lt;/code&gt;是无法通过校验的，需要传入&lt;code&gt;id&lt;/code&gt;的，即为&lt;code&gt;postid&lt;/code&gt;的值。&lt;/p&gt;

&lt;p&gt;在进入&lt;code&gt;wp_crop_image()&lt;/code&gt;时还需要传递裁剪后的图片宽度和高度信息，所以还需要增加c&lt;code&gt;ropDetails[dst_width]&lt;/code&gt;和&lt;code&gt;cropDetails[dst_height]&lt;/code&gt;两个参数。&lt;/p&gt;

&lt;p&gt;&lt;code&gt;wp_crop_image()&lt;/code&gt;方法如下&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1252261399.cos-website.ap-beijing.myqcloud.com/images/20190221183701.png&#34; alt=&#34;&#34; /&gt;&lt;/p&gt;

&lt;p&gt;从数据库取出&lt;code&gt;_wp_attached_file&lt;/code&gt;后并没有做检查，形如&lt;code&gt;2019/02/admin.jpeg?../../1.png&lt;/code&gt;的文件无法被找到，于是进入&lt;code&gt;_load_image_to_edit_path()&lt;/code&gt;通过&lt;code&gt;wp_get_attachment_url()&lt;/code&gt;方法生成本地&lt;code&gt;url&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1252261399.cos-website.ap-beijing.myqcloud.com/images/20190221184123.png&#34; alt=&#34;&#34; /&gt;&lt;/p&gt;

&lt;p&gt;随后实例化一个&lt;code&gt;WP_Image_Editor&lt;/code&gt;用来裁剪并生成裁剪后的图片，之后调用&lt;code&gt;wp_mkdir_p()&lt;/code&gt;方法创建文件夹，含有&lt;code&gt;../&lt;/code&gt;的参数进入该方法后同样没有经过过滤，最终执行到&lt;code&gt;mkdir&lt;/code&gt;创建文件夹&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-php&#34;&gt;mkdir( $target, $dir_perms, true)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;此时的&lt;code&gt;target&lt;/code&gt;值是这个样子，穿越目录后在&lt;code&gt;2019&lt;/code&gt;目录下创建&lt;code&gt;1&lt;/code&gt;文件夹，并生成&lt;code&gt;cropped-1.png&lt;/code&gt;文件&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;D:\phpStudy\PHPTutorial\WWW\wordpress-4.9.8/wp-content/uploads/2019/02/admin.jpeg?../../../1
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;注意：此处有一个坑，我们观察上面的&lt;code&gt;url&lt;/code&gt;，在&lt;code&gt;mkdir&lt;/code&gt;的时候会把&lt;code&gt;admin.jpeg?../&lt;/code&gt;作为一个目录，而在Windows下的目录不能出现&lt;code&gt;?&lt;/code&gt;，所以上面的payload在Windows下无法成功，经过测试，&lt;code&gt;#&lt;/code&gt;可以存在于Windows目录，因此在Windows下的payload如下所示：&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;meta_input[_wp_attached_file]=2019/02/admin.jpeg#../../../1/1.png
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;写入数据库中即为&lt;code&gt;2019/02/admin.jpeg#../../../1/1.png&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;最终构造第二个数据包触发裁剪图片并保存：&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1252261399.cos-website.ap-beijing.myqcloud.com/images/20190221182857.png&#34; alt=&#34;&#34; /&gt;&lt;/p&gt;

&lt;p&gt;最终在指定目录下生成裁剪后的图片文件，以&lt;code&gt;cropped-&lt;/code&gt;作为前缀&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1252261399.cos-website.ap-beijing.myqcloud.com/images/20190221232341.png&#34; alt=&#34;&#34; /&gt;&lt;/p&gt;

&lt;p&gt;这样子我们可以制作一张图片马，在主题文件夹下生成，或者指定任意目录，被&lt;code&gt;include&lt;/code&gt;后即可造成代码执行。&lt;/p&gt;

&lt;h3 id=&#34;0x04-lfi-to-rce&#34;&gt;0x04 LFI to RCE&lt;/h3&gt;

&lt;p&gt;到目前为止我们可以把含有恶意代码的图片写入任意目录，下一步就是想办法包含这个文件。&lt;/p&gt;

&lt;p&gt;在&lt;code&gt;Wordpress&lt;/code&gt;中，访问一篇文章或者任意页面，都需要从数据库取出相应的模板文件位置并由浏览器渲染出来。注意到上面截图，&lt;code&gt;wp_postmeta&lt;/code&gt;数据库中有个字段名称为&lt;code&gt;_wp_page_template&lt;/code&gt;，这个字段用来保存加载页面所需要的模板文件，默认为&lt;code&gt;default&lt;/code&gt;，&lt;code&gt;wordpress&lt;/code&gt;程序根据需要加载的页面类型从当前主题下选择需要的模板，例如访问一篇单独的文章，这个过程会拼凑出文件名并检查主题下的这些文件是否存在，如果存在则包含进来，相关方法是&lt;code&gt;locate_template()&lt;/code&gt;和&lt;code&gt;load_template()&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1252261399.cos-website.ap-beijing.myqcloud.com/images/20190225145624.png&#34; alt=&#34;&#34; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1252261399.cos-website.ap-beijing.myqcloud.com/images/20190225145650.png&#34; alt=&#34;&#34; /&gt;&lt;/p&gt;

&lt;p&gt;搜索发现实现从数据库取出&lt;code&gt;_wp_page_template&lt;/code&gt;变量的方法是&lt;code&gt;get_page_template_slug()&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1252261399.cos-website.ap-beijing.myqcloud.com/images/20190225150445.png&#34; alt=&#34;&#34; /&gt;&lt;/p&gt;

&lt;p&gt;接着发现调用&lt;code&gt;get_page_template_slug()&lt;/code&gt;方法的&lt;code&gt;get_single_template()&lt;/code&gt;方法，其最后返回的是查找模板函数，即&lt;code&gt;get_query_template()&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1252261399.cos-website.ap-beijing.myqcloud.com/images/20190225150545.png&#34; alt=&#34;&#34; /&gt;&lt;/p&gt;

&lt;p&gt;而正是在&lt;code&gt;get_query_template()&lt;/code&gt;中，执行了定位模板文件的操作&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1252261399.cos-website.ap-beijing.myqcloud.com/images/20190225150712.png&#34; alt=&#34;&#34; /&gt;&lt;/p&gt;

&lt;p&gt;至此一条利用链就串起来了，利用第一个漏洞覆盖数据库中的&lt;code&gt;_wp_page_template&lt;/code&gt;值，修改为包含恶意代码的图片所在路径，在页面加载的过程中&lt;code&gt;wordpress&lt;/code&gt;查询并定位该文件，包含后造成代码执行。&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Wordpress&lt;/code&gt;中处理图片相关的库有两个，分别是&lt;code&gt;Imagick&lt;/code&gt;和&lt;code&gt;GD&lt;/code&gt;，优先选择使用&lt;code&gt;Imagick&lt;/code&gt;，而&lt;code&gt;Imagick&lt;/code&gt;处理图片时不处理&lt;code&gt;EXIF&lt;/code&gt;信息，因此可以把恶意代码设置在&lt;code&gt;EXIF&lt;/code&gt;部分，经过裁剪后会保留&lt;code&gt;EXIF&lt;/code&gt;信息，此时再进行包含就能造成代码执行。&lt;/p&gt;

&lt;p&gt;在选择相应图片库处理图片时，如果此时加载的是&lt;code&gt;Imagick&lt;/code&gt;，在&lt;code&gt;$editor-&amp;gt;load()&lt;/code&gt;时会创建&lt;code&gt;Imagick()&lt;/code&gt;对象，然后尝试读取远程图片地址。此时需要注意的是，高版本的&lt;code&gt;Imagick&lt;/code&gt;库不支持远程链接，测试&lt;code&gt;Imagick-6.9.7&lt;/code&gt;版本正常创建并写入图片&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-php&#34;&gt;$implementation = _wp_image_editor_choose( $args );

if ( $implementation ) {
    $editor = new $implementation( $path );
    $loaded = $editor-&amp;gt;load();

    if ( is_wp_error( $loaded ) )
        return $loaded;

    return $editor;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;pre&gt;&lt;code class=&#34;language-php&#34;&gt;$this-&amp;gt;image = new Imagick();
//...
$this-&amp;gt;image-&amp;gt;readImage( $filename );
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;复现：&lt;/p&gt;

&lt;p&gt;1.上传图片，更新描述信息并保存，抓包修改&lt;code&gt;meta_input[_wp_attached_file]&lt;/code&gt;，目录穿越至当前主题文件夹&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1252261399.cos-website.ap-beijing.myqcloud.com/images/20190226172313.png&#34; alt=&#34;&#34; /&gt;&lt;/p&gt;

&lt;p&gt;2.裁剪图片并在主题文件夹下生成裁剪后图片&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1252261399.cos-website.ap-beijing.myqcloud.com/images/20190226173532.png&#34; alt=&#34;&#34; /&gt;&lt;/p&gt;

&lt;p&gt;3.上传一个附件，更新描述信息并抓包，修改&lt;code&gt;meta_input[_wp_page_template]&lt;/code&gt;，加载模板的时候自动包含该图片，代码执行成功&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1252261399.cos-website.ap-beijing.myqcloud.com/images/20190226171510.png&#34; alt=&#34;&#34; /&gt;&lt;/p&gt;

&lt;h3 id=&#34;0x05-关于mkdir&#34;&gt;0x05 关于mkdir&lt;/h3&gt;

&lt;p&gt;在漏洞调试过程中最后一步&lt;code&gt;$editor-&amp;gt;save( $dst_file )&lt;/code&gt;过程，最终执行到的是&lt;code&gt;wp_mkdir_p()&lt;/code&gt;方法中的&lt;code&gt;mkdir&lt;/code&gt;函数&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-php&#34;&gt;mkdir( $target, $dir_perms, true)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;关于&lt;code&gt;mkdir()&lt;/code&gt;函数，需要注意的是&lt;code&gt;mode&lt;/code&gt;参数和&lt;code&gt;recursive&lt;/code&gt;参数，分别代表了创建的文件夹权限和是否递归创建，这两个参数的不同导致在&lt;code&gt;Linux&lt;/code&gt;平台和&lt;code&gt;Windows&lt;/code&gt;平台的结果不一致&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1252261399.cos-website.ap-beijing.myqcloud.com/images/20190222093526.png&#34; alt=&#34;&#34; /&gt;&lt;/p&gt;

&lt;p&gt;在上面漏洞链中，进入最终&lt;code&gt;mkdir()&lt;/code&gt;的参数是这样的&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-php&#34;&gt;mkdir( &#39;D:\phpStudy\PHPTutorial\WWW\wordpress-4.9.8/wp-content/uploads/2019/02/admin.jpeg?../../../1&#39;, 511, true)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1252261399.cos-website.ap-beijing.myqcloud.com/images/20190222094608.png&#34; alt=&#34;&#34; /&gt;&lt;/p&gt;

&lt;p&gt;单独把&lt;code&gt;path&lt;/code&gt;拿出来测试，在第三个参数&lt;code&gt;recursive&lt;/code&gt;分别为&lt;code&gt;true&lt;/code&gt;和&lt;code&gt;false&lt;/code&gt;时，测试结果如下&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1252261399.cos-website.ap-beijing.myqcloud.com/images/20190222095108.png&#34; alt=&#34;&#34; /&gt;&lt;/p&gt;

&lt;p&gt;这里导致结果不一致是因为Windows下文件夹对&lt;code&gt;?&lt;/code&gt;的处理，当指定递归创建模式时，系统会尝试创建名为&lt;code&gt;admin.jpeg?..&lt;/code&gt;的目录，又因为Windows下的目录不能含有&lt;code&gt;?&lt;/code&gt;，因此&lt;code&gt;recursive=true&lt;/code&gt;时是创建失败的，导致&lt;code&gt;wordpress&lt;/code&gt;最终生成图片也无法成功。而在Linux下可以没有&lt;code&gt;?&lt;/code&gt;的限制，&lt;code&gt;payload&lt;/code&gt;可以成功触发。&lt;/p&gt;

&lt;p&gt;要想在&lt;code&gt;Windows&lt;/code&gt;下利用漏洞，一个技巧是利用&lt;code&gt;#&lt;/code&gt;字符，&lt;code&gt;#&lt;/code&gt;在&lt;code&gt;url&lt;/code&gt;中表示为网页位置指定标识符，只在浏览器中起作用，对解析资源时是忽略后面的字符的，因此在&lt;code&gt;wordpress&lt;/code&gt;中两个方式尝试获取图片资源时同样会出现不一致，导致漏洞产生。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;更新：&lt;/strong&gt;此处是否检查&lt;code&gt;?&lt;/code&gt;等不合法字符与&lt;code&gt;php&lt;/code&gt;的线程安全模式相关，具体如下。&lt;/p&gt;

&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th align=&#34;center&#34;&gt;Windows&lt;/th&gt;
&lt;th align=&#34;center&#34;&gt;&lt;strong&gt;thread-safe&lt;/strong&gt;&lt;/th&gt;
&lt;th align=&#34;center&#34;&gt;&lt;strong&gt;non-thread safe&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;

&lt;tbody&gt;
&lt;tr&gt;
&lt;td align=&#34;center&#34;&gt;&lt;strong&gt;recursive=false&lt;/strong&gt;&lt;/td&gt;
&lt;td align=&#34;center&#34;&gt;fail (No error)&lt;/td&gt;
&lt;td align=&#34;center&#34;&gt;&lt;strong&gt;success&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td align=&#34;center&#34;&gt;&lt;strong&gt;recursive=true&lt;/strong&gt;&lt;/td&gt;
&lt;td align=&#34;center&#34;&gt;fail (Invalid path)&lt;/td&gt;
&lt;td align=&#34;center&#34;&gt;fail (Invalid path)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;关于这块的详细分析可以参考 &lt;a href=&#34;https://kylingit.com/blog/%E5%AF%B9php%E4%B8%AD%E7%9A%84mkdir%E5%87%BD%E6%95%B0%E7%9A%84%E7%A0%94%E7%A9%B6/&#34;&gt;对PHP中的mkdir()函数的研究&lt;/a&gt;&lt;/p&gt;

&lt;h3 id=&#34;0x06-poc&#34;&gt;0x06 PoC&lt;/h3&gt;

&lt;p&gt;见上面分析&lt;/p&gt;

&lt;h3 id=&#34;0x07-总结&#34;&gt;0x07 总结&lt;/h3&gt;

&lt;p&gt;在分析过程中踩了不少坑，每一个都浪费了不少时间，简单记录避免再次踩中。主要的有这么几个：&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;code&gt;Wordpress&lt;/code&gt;自动更新；&lt;/li&gt;
&lt;li&gt;需要手动修改触发裁剪函数的&lt;code&gt;action&lt;/code&gt;；&lt;/li&gt;
&lt;li&gt;&lt;code&gt;mkdir&lt;/code&gt;创建文件夹时特殊字符的问题；&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Imagick&lt;/code&gt;读取远程文件的问题；&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;这个漏洞主要成因在于我们可以通过参数传递任意值覆盖数据库中的字段，从而引入&lt;code&gt;../&lt;/code&gt;构成目录穿越，在裁剪图片后保存文件时并没有对文件目录做检查，造成目录穿越漏洞，最终可以写入恶意图片被包含或者通过&lt;code&gt;Imagick&lt;/code&gt;漏洞触发远程代码执行，利用链挺巧妙，值得学习。&lt;/p&gt;

&lt;p&gt;参考：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://blog.ripstech.com/2019/wordpress-image-remote-code-execution/&#34;&gt;https://blog.ripstech.com/2019/wordpress-image-remote-code-execution/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/WordPress/WordPress/commit/43bdb0e193955145a5ab1137890bb798bce5f0d2#diff-c3d5c535db5622f3b0242411ee5f9dfd&#34;&gt;https://github.com/WordPress/WordPress/commit/43bdb0e193955145a5ab1137890bb798bce5f0d2#diff-c3d5c535db5622f3b0242411ee5f9dfd&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;script&gt;pangu.spacingPage();&lt;/script&gt;
</description>
    </item>
    
    <item>
      <title>ThinkPHP 5.0.x-5.0.23、5.1.x、5.2.x 全版本远程代码执行漏洞分析</title>
      <link>https://kylingit.com/blog/thinkphp-5.0.x-5.0.235.1.x5.2.x-%E5%85%A8%E7%89%88%E6%9C%AC%E8%BF%9C%E7%A8%8B%E4%BB%A3%E7%A0%81%E6%89%A7%E8%A1%8C%E6%BC%8F%E6%B4%9E%E5%88%86%E6%9E%90/</link>
      <pubDate>Sat, 12 Jan 2019 14:18:20 +0000</pubDate>
      
      <guid>https://kylingit.com/blog/thinkphp-5.0.x-5.0.235.1.x5.2.x-%E5%85%A8%E7%89%88%E6%9C%AC%E8%BF%9C%E7%A8%8B%E4%BB%A3%E7%A0%81%E6%89%A7%E8%A1%8C%E6%BC%8F%E6%B4%9E%E5%88%86%E6%9E%90/</guid>
      <description>

&lt;script src=&#34;https://blog-1252261399.cos-website.ap-beijing.myqcloud.com/pangu.js&#34;&gt;&lt;/script&gt;

&lt;h3 id=&#34;0x01-概述&#34;&gt;0x01 概述&lt;/h3&gt;

&lt;p&gt;1月11日，&lt;code&gt;ThinkPHP&lt;/code&gt;官方发布新版本&lt;code&gt;5.0.24&lt;/code&gt;，在1月14日和15日又接连发布两个更新，这三次更新都修复了一个安全问题，该问题可能导致远程代码执行 ，这是&lt;code&gt;ThinkPHP&lt;/code&gt;近期的第二个高危漏洞，两个漏洞均是无需登录即可远程触发，危害极大。&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;公告&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href=&#34;https://blog.thinkphp.cn/910675&#34;&gt;https://blog.thinkphp.cn/910675&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&#34;http://blog.nsfocus.net/thinkphp-5-0-5-0-23-rce/&#34;&gt;http://blog.nsfocus.net/thinkphp-5-0-5-0-23-rce/&lt;/a&gt;&lt;/p&gt;

&lt;h3 id=&#34;0x02-影响版本&#34;&gt;0x02 影响版本&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;ThinkPHP 5.0.x ~ 5.0.23&lt;/p&gt;

&lt;p&gt;ThinkPHP 5.1.x ~ 5.1.31&lt;/p&gt;

&lt;p&gt;ThinkPHP 5.2.0beta1&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3 id=&#34;0x03-环境搭建&#34;&gt;0x03 环境搭建&lt;/h3&gt;

&lt;p&gt;选择&lt;code&gt;5.0.22&lt;/code&gt;完整版和&lt;code&gt;5.1.31&lt;/code&gt;版本进行复现分析&lt;/p&gt;

&lt;h3 id=&#34;0x04-漏洞分析&#34;&gt;0x04 漏洞分析&lt;/h3&gt;

&lt;h4 id=&#34;一-5-0-x-版本&#34;&gt;一、&lt;code&gt;5.0.x&lt;/code&gt;版本&lt;/h4&gt;

&lt;p&gt;我们知道可以通过&lt;code&gt;http://127.0.0.1/public/index.php?s=index&lt;/code&gt;的方式通过&lt;code&gt;s&lt;/code&gt;参数传递具体的路由，具体调用如下&lt;/p&gt;

&lt;p&gt;&lt;code&gt;index.php&lt;/code&gt;&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-php&#34;&gt;require __DIR__ . &#39;/../thinkphp/start.php&#39;;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;code&gt;start.php&lt;/code&gt;&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-php&#34;&gt;App::run()-&amp;gt;send();
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;跟进&lt;code&gt;run()&lt;/code&gt;方法&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1252261399.cos-website.ap-beijing.myqcloud.com/images/20190112152929.png&#34; alt=&#34;&#34; /&gt;&lt;/p&gt;

&lt;p&gt;可以看到在进入&lt;code&gt;self::exec($dispatch, $config)&lt;/code&gt;前，&lt;code&gt;$dispatch&lt;/code&gt;的值是通过&lt;/p&gt;

&lt;p&gt;&lt;code&gt;$dispatch = self::routeCheck($request, $config)&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;设置的，这时候如果&lt;code&gt;debug&lt;/code&gt;模式开启，就会调用&lt;code&gt;$request-&amp;gt;param()&lt;/code&gt;，也就是下面&lt;code&gt;exec()&lt;/code&gt;中会调用到的函数，经过下面分析就能发现，在&lt;code&gt;debug&lt;/code&gt;模式开启时就能直接触发漏洞，原理是一样的。&lt;/p&gt;

&lt;p&gt;进入&lt;code&gt;exec()&lt;/code&gt;方法看一下：&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1252261399.cos-website.ap-beijing.myqcloud.com/images/20190112153147.png&#34; alt=&#34;&#34; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;exec()&lt;/code&gt;方法根据&lt;code&gt;$dispatch&lt;/code&gt;的值选择进入不同的分支，当进入&lt;code&gt;method&lt;/code&gt;分支时，调用&lt;code&gt;Request::instance()-&amp;gt;param()&lt;/code&gt;方法，跟进&lt;code&gt;param()&lt;/code&gt;，看到调用了&lt;code&gt;Request&lt;/code&gt;类的&lt;code&gt;method()&lt;/code&gt;方法 ：&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1252261399.cos-website.ap-beijing.myqcloud.com/images/20190114120946.png&#34; alt=&#34;&#34; /&gt;&lt;/p&gt;

&lt;p&gt;其中&lt;code&gt;method()&lt;/code&gt;方法就是补丁修改的位置，在这个方法中，如果&lt;code&gt;method&lt;/code&gt;等于&lt;code&gt;true&lt;/code&gt;，则调用&lt;code&gt;$this-&amp;gt;server()&lt;/code&gt;方法：&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1252261399.cos-website.ap-beijing.myqcloud.com/images/20190112153449.png&#34; alt=&#34;&#34; /&gt;&lt;/p&gt;

&lt;p&gt;在&lt;code&gt;server()&lt;/code&gt;方法中调用&lt;code&gt;$this-&amp;gt;input&lt;/code&gt;方法：&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1252261399.cos-website.ap-beijing.myqcloud.com/images/20190112154611.png&#34; alt=&#34;&#34; /&gt;&lt;/p&gt;

&lt;p&gt;接着调用了&lt;code&gt;filterValue()&lt;/code&gt;方法：&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1252261399.cos-website.ap-beijing.myqcloud.com/images/20190112154923.png&#34; alt=&#34;&#34; /&gt;&lt;/p&gt;

&lt;p&gt;而&lt;code&gt;filterValue()&lt;/code&gt;则调用了&lt;code&gt;call_user_func()&lt;/code&gt;函数，如果两个参数均可控，则会造成命令执行：&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1252261399.cos-website.ap-beijing.myqcloud.com/images/20190112175411.png&#34; alt=&#34;&#34; /&gt;&lt;/p&gt;

&lt;p&gt;此时的调用栈如下：&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1252261399.cos-website.ap-beijing.myqcloud.com/images/20190114104035.png&#34; alt=&#34;&#34; /&gt;&lt;/p&gt;

&lt;p&gt;回头看一下&lt;code&gt;$filter&lt;/code&gt;和&lt;code&gt;$value&lt;/code&gt;参数从哪里来：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;$filter&lt;/code&gt;：&lt;/li&gt;
&lt;/ul&gt;

&lt;pre&gt;&lt;code class=&#34;language-php&#34;&gt;$filter = $this-&amp;gt;getFilter($filter, $default);
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;在&lt;code&gt;getFilter()&lt;/code&gt;中设置了&lt;code&gt;$filter&lt;/code&gt;值：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-php&#34;&gt;$filter = $filter ?: $this-&amp;gt;filter;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;也即由&lt;code&gt;$this-&amp;gt;filter&lt;/code&gt;决定&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;$value&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;$value&lt;/code&gt;为第一个参数&lt;code&gt;$data&lt;/code&gt;，即为传入数组的值，由&lt;code&gt;$this-&amp;gt;server&lt;/code&gt;决定&lt;/p&gt;

&lt;p&gt;所以最终的问题就是如何从请求中传入&lt;code&gt;$this-&amp;gt;filter&lt;/code&gt;和&lt;code&gt;$this-&amp;gt;server&lt;/code&gt;这两个值，构造&lt;code&gt;call_user_func()&lt;/code&gt;的参数触发漏洞。&lt;/p&gt;

&lt;p&gt;回到最开始的&lt;code&gt;run()&lt;/code&gt;方法，其中：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-php&#34;&gt;$dispatch = self::routeCheck($request, $config);
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;code&gt;$dispatch&lt;/code&gt; 的值通过&lt;code&gt;routeCheck()&lt;/code&gt;方法设置，跟进&lt;code&gt;routeCheck()&lt;/code&gt;方法：&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1252261399.cos-website.ap-beijing.myqcloud.com/images/20190112155407.png&#34; alt=&#34;&#34; /&gt;&lt;/p&gt;

&lt;p&gt;调用了&lt;code&gt;check()&lt;/code&gt;方法：&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1252261399.cos-website.ap-beijing.myqcloud.com/images/20190112155704.png&#34; alt=&#34;&#34; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;check()&lt;/code&gt;方法中根据不同的&lt;code&gt;$rules&lt;/code&gt;值返回不同的结果，而&lt;code&gt;$rules&lt;/code&gt;的值由&lt;code&gt;$method&lt;/code&gt;决定，&lt;code&gt;$method&lt;/code&gt;则由&lt;code&gt;$request-&amp;gt;method()&lt;/code&gt;返回值取小写获得，所以再次回到&lt;code&gt;$request-&amp;gt;method()&lt;/code&gt;方法，这次没有参数&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1252261399.cos-website.ap-beijing.myqcloud.com/images/20190112153449.png&#34; alt=&#34;&#34; /&gt;&lt;/p&gt;

&lt;p&gt;如果&lt;code&gt;$method&lt;/code&gt;不等于&lt;code&gt;true&lt;/code&gt;，则会取配置选项&lt;code&gt;var_method&lt;/code&gt;，该值为&lt;code&gt;_method&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1252261399.cos-website.ap-beijing.myqcloud.com/images/20190112153759.png&#34; alt=&#34;&#34; /&gt;&lt;/p&gt;

&lt;p&gt;然后调用&lt;code&gt;$this-&amp;gt;{$this-&amp;gt;method}($_POST);&lt;/code&gt;语句，此时假设我们控制了&lt;code&gt;$method&lt;/code&gt;的值，也就意味着可以调用&lt;code&gt;Request&lt;/code&gt;类的任意方法，而当调用构造方法&lt;code&gt;__construct()&lt;/code&gt;时，就可以覆盖&lt;code&gt;Request&lt;/code&gt;类的任意成员变量，也就是上面分析的&lt;code&gt;$this-&amp;gt;filter&lt;/code&gt;和&lt;code&gt;$this-&amp;gt;server&lt;/code&gt;两个值，同时也可以覆盖&lt;code&gt;$this-&amp;gt;method&lt;/code&gt;，直接指定了&lt;code&gt;check()&lt;/code&gt;方法中的&lt;code&gt;$method&lt;/code&gt;值。&lt;/p&gt;

&lt;h5 id=&#34;1-构造-poc&#34;&gt;1. 构造&lt;code&gt;PoC&lt;/code&gt;&lt;/h5&gt;

&lt;p&gt;首先要主动触发&lt;code&gt;Request&lt;/code&gt;类的构造函数，通过参数&lt;code&gt;_method=__construct&lt;/code&gt;传入，进入到&lt;code&gt;__construct&lt;/code&gt;方法，该方法把参数遍历并设置值：&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1252261399.cos-website.ap-beijing.myqcloud.com/images/20190112163221.png&#34; alt=&#34;&#34; /&gt;&lt;/p&gt;

&lt;p&gt;所以我们可以传入&lt;strong&gt;&lt;code&gt;filter=system&lt;/code&gt;&lt;/strong&gt;来设置&lt;code&gt;$this-&amp;gt;filter&lt;/code&gt;的值&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;此处&lt;code&gt;filter&lt;/code&gt;不是数组也可以，因为在&lt;code&gt;getFilter()&lt;/code&gt;中虽然对&lt;code&gt;filter&lt;/code&gt;是字符串的情况进行了按&lt;code&gt;,&lt;/code&gt;分割，但是传入一个值的情况下不影响最终的返回值&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;再看&lt;code&gt;$this-&amp;gt;server&lt;/code&gt;，在调用&lt;code&gt;$this-&amp;gt;server(&#39;REQUEST_METHOD&#39;)&lt;/code&gt;时指定了键值，所以通过传入&lt;code&gt;server&lt;/code&gt;数组即可&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;server[REQUEST_METHOD]=id&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;然后我们注意到上面&lt;code&gt;check()&lt;/code&gt;方法，&lt;/p&gt;

&lt;p&gt;&lt;code&gt;$rules = isset(self::$rules[$method]) ? self::$rules[$method] : [];&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;它的返回值由&lt;code&gt;$rules&lt;/code&gt;决定，而&lt;code&gt;$rules&lt;/code&gt;的值取决于键值&lt;code&gt;$method&lt;/code&gt;，当我们指定&lt;code&gt;$method&lt;/code&gt;为&lt;code&gt;get&lt;/code&gt;时，可以正确获取到路由信息，从而通过&lt;code&gt;checkRoute()&lt;/code&gt;检查，此时我们通过指定&lt;strong&gt;&lt;code&gt;method=get&lt;/code&gt;&lt;/strong&gt;覆盖&lt;code&gt;$this-&amp;gt;method&lt;/code&gt;的值即可&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1252261399.cos-website.ap-beijing.myqcloud.com/images/20190112173807.png&#34; alt=&#34;&#34; /&gt;&lt;/p&gt;

&lt;p&gt;最终的&lt;code&gt;PoC&lt;/code&gt;：&lt;/p&gt;

&lt;p&gt;&lt;code&gt;_method=__construct&amp;amp;filter=system&amp;amp;method=get&amp;amp;server[REQUEST_METHOD]=id&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1252261399.cos-website.ap-beijing.myqcloud.com/images/20190112163746.png&#34; alt=&#34;&#34; /&gt;&lt;/p&gt;

&lt;p&gt;调用栈如下图所示&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1252261399.cos-website.ap-beijing.myqcloud.com/images/20190112175904.png&#34; alt=&#34;&#34; /&gt;&lt;/p&gt;

&lt;h5 id=&#34;2-流程图&#34;&gt;2. 流程图&lt;/h5&gt;

&lt;p&gt;整个漏洞的调用流程图如下所示：&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1252261399.cos-website.ap-beijing.myqcloud.com/images/20190116110438.png&#34; alt=&#34;&#34; /&gt;&lt;/p&gt;

&lt;h4 id=&#34;二-5-1-x-5-2-x-版本&#34;&gt;二、&lt;code&gt;5.1.x&lt;/code&gt;/&lt;code&gt;5.2.x&lt;/code&gt;版本&lt;/h4&gt;

&lt;p&gt;在&lt;code&gt;5.1&lt;/code&gt;和&lt;code&gt;5.2&lt;/code&gt;版本上，这个变量覆盖依然存在，我们同样可以通过&lt;code&gt;_method&lt;/code&gt;参数覆盖&lt;code&gt;var_method&lt;/code&gt;，并最终执行到&lt;code&gt;Request::input()&lt;/code&gt;方法，通过&lt;code&gt;array_walk_recursive&lt;/code&gt;把传入的数组传给回调函数&lt;code&gt;filterValue&lt;/code&gt;，最终也是在&lt;code&gt;filterValue&lt;/code&gt;中完成命令执行，具体调用如下&lt;/p&gt;

&lt;p&gt;当传入&lt;code&gt;_method&lt;/code&gt;参数为&lt;code&gt;filter&lt;/code&gt;时，覆盖了&lt;code&gt;Request&lt;/code&gt;原始的&lt;code&gt;filter&lt;/code&gt;成员，在经过路由检查进入&lt;code&gt;Request::instance()-&amp;gt;param()&lt;/code&gt;方法时，经过&lt;code&gt;$this-&amp;gt;method(true)调用，&lt;/code&gt;返回的&lt;code&gt;$method&lt;/code&gt;值为&lt;code&gt;POST&lt;/code&gt;，于是进入&lt;code&gt;post&lt;/code&gt;分支，调用&lt;code&gt;input()&lt;/code&gt;方法，由于第一个参数为空，返回我们传入的&lt;code&gt;post&lt;/code&gt;值&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1252261399.cos-website.ap-beijing.myqcloud.com/images/20190116095414.png&#34; alt=&#34;&#34; /&gt;&lt;/p&gt;

&lt;p&gt;然后把数组合并到&lt;code&gt;$this-&amp;gt;param&lt;/code&gt;，接着再次调用&lt;code&gt;input()&lt;/code&gt;方法，经过&lt;code&gt;$this-&amp;gt;getFilter&lt;/code&gt;返回&lt;code&gt;filter&lt;/code&gt;值，由于此时&lt;code&gt;$data&lt;/code&gt;是一个数组(即&lt;code&gt;$this-&amp;gt;param&lt;/code&gt;)，于是进入&lt;code&gt;if&lt;/code&gt;分支，经过&lt;code&gt;array_walk_recursive()&lt;/code&gt;函数把数组传给回调函数&lt;code&gt;filterValue&lt;/code&gt;，遍历键值后同样由&lt;code&gt;call_user_func&lt;/code&gt;完成命令执行&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-php&#34;&gt;if (is_array($data)) {
    array_walk_recursive($data, [$this, &#39;filterValue&#39;], $filter);
    if (version_compare(PHP_VERSION, &#39;7.1.0&#39;, &#39;&amp;lt;&#39;)) {
        // 恢复PHP版本低于 7.1 时 array_walk_recursive 中消耗的内部指针
        $this-&amp;gt;arrayReset($data);
    }
} else {
    $this-&amp;gt;filterValue($data, $name, $filter);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;h5 id=&#34;1-构造-poc-1&#34;&gt;1. 构造&lt;code&gt;PoC&lt;/code&gt;&lt;/h5&gt;

&lt;pre&gt;&lt;code class=&#34;language-php&#34;&gt;a=system&amp;amp;b=id&amp;amp;_method=filter
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;需要在程序加入忽略异常提示：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-php&#34;&gt;error_reporting(0);
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;调用栈如图&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1252261399.cos-website.ap-beijing.myqcloud.com/images/20190116095551.png&#34; alt=&#34;&#34; /&gt;&lt;/p&gt;

&lt;h5 id=&#34;2-流程图-1&#34;&gt;2. 流程图&lt;/h5&gt;

&lt;p&gt;&lt;code&gt;5.1.x&lt;/code&gt;版本的漏洞调用流程图如下所示：&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1252261399.cos-website.ap-beijing.myqcloud.com/images/20190116104019.png&#34; alt=&#34;&#34; /&gt;&lt;/p&gt;

&lt;h3 id=&#34;0x05-补丁分析&#34;&gt;0x05 补丁分析&lt;/h3&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1252261399.cos-website.ap-beijing.myqcloud.com/images/20190114134401.png&#34; alt=&#34;&#34; /&gt;&lt;/p&gt;

&lt;p&gt;在三个版本的更新补丁中，限制了&lt;code&gt;$this-&amp;gt;method&lt;/code&gt;为&lt;code&gt;GET&lt;/code&gt;，&lt;code&gt;POST&lt;/code&gt;，&lt;code&gt;DELETE&lt;/code&gt;，&lt;code&gt;PUT&lt;/code&gt;，&lt;code&gt;PATCH&lt;/code&gt;这几个方法，因此不能从外部传入方法名再调用&lt;code&gt;Request&lt;/code&gt;类的任意方法或是覆盖原有变量。&lt;/p&gt;

&lt;p&gt;补丁链接：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;5.0.24：&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href=&#34;https://github.com/top-think/framework/commit/4a4b5e64fa4c46f851b4004005bff5f3196de003&#34;&gt;https://github.com/top-think/framework/commit/4a4b5e64fa4c46f851b4004005bff5f3196de003&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;5.1.31：&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href=&#34;https://github.com/top-think/framework/commit/2454cebcdb6c12b352ac0acd4a4e6b25b31982e6&#34;&gt;https://github.com/top-think/framework/commit/2454cebcdb6c12b352ac0acd4a4e6b25b31982e6&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;5.2-beta.2：&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href=&#34;https://github.com/top-think/framework/commit/7c24500e463704583e0778b7ec6efce607ddef5f&#34;&gt;https://github.com/top-think/framework/commit/7c24500e463704583e0778b7ec6efce607ddef5f&lt;/a&gt;&lt;/p&gt;

&lt;h3 id=&#34;0x06-总结&#34;&gt;0x06 总结&lt;/h3&gt;

&lt;p&gt;这三漏洞本质上都是变量覆盖漏洞，在一处存在缺陷的方法中没有对用户输入做严格判断，通过传递&lt;code&gt;_method&lt;/code&gt;参数覆盖了配置文件的&lt;code&gt;_method&lt;/code&gt;，导致可以访问&lt;code&gt;Request&lt;/code&gt;类的任意函数，而在&lt;code&gt;Request&lt;/code&gt;的构造函数中又创建了恶意的成员变量，导致后面的命令执行；而在&lt;code&gt;5.1&lt;/code&gt;和&lt;code&gt;5.2&lt;/code&gt;版本中则是直接覆盖了过滤器，在忽略运行异常的情况下会触发漏洞，整个利用链可以说是非常巧妙了。&lt;/p&gt;

&lt;script&gt;pangu.spacingPage();&lt;/script&gt;
</description>
    </item>
    
  </channel>
</rss>