海豚命令执行复现

2022-06-28 6,811


概述


想复现命令执行的漏洞,情不知所起,来漏洞库看看。就这个哥们了。开始下载安装。

安装



安装效果图

前台



后台


验证



点击进去发现,命令执行,,,还是tp5。不就是那个RCE吗。。来来,上个payload看效果。



流程梳理

那就带大家看看代码流程图吧。首先分析下这个payload,thinkapp这个是类文件,invokefunction这个是方法名,后面的都是参数。打断点发请求,过程如下图所示:



图中的这段代码,反射的高级用法,触发函数调用。也就是call_user_func_array这个方法,此方法调用说明如下:

image.png

第一个参数传入的system方法。这个方法调用说明如下:

/**
 * Execute an external program and display the output 
 * @link https://php.net/manual/en/function.system.php 
 * @param string $command <p> 
 * The command that will be executed. 
 * </p> 
 * @param int $return_var [optional] <p> 
 * If the return_var argument is present, then the 
 * return status of the executed command will be written to this 
 * variable. 
 * </p> 
 * @return string|false the last line of the command output on success, and false 
 * on failure. 
 * @since 4.0 
 * @since 5.0 
 */function system ($command, &$return_var = null) {}

接着给system传入的系统命令whoami/ls作为验证判断条件,在验证环节,就出来了计算机当前用户。

重点

代码看着贼简单,但是要明白里面的访问方式,这个就得聊聊了。同时也会明白为什么会产生这样的漏洞。

在tp里,如果你访问了一个不存在的类文件时,系统会帮助用户搜索加载,通过这个spl_autoload_register函数。如下代码:

  // 注册自动加载机制  
    public static function register($autoload = '')
{        // 注册系统自动加载        
         spl_autoload_register($autoload ?: 'think\Loader::autoload', true, true);        // 注册命名空间定义        
         self::addNamespace([            'think'    => LIB_PATH . 'think' . DS,            'behavior' => LIB_PATH . 'behavior' . DS,            'traits'   => LIB_PATH . 'traits' . DS,        
         ]);        // 加载类库映射文件        
         if (is_file(RUNTIME_PATH . 'classmap' . EXT)) {            self::addClassMap(__include_file(RUNTIME_PATH . 'classmap' .EXT));        
          }        // Composer自动加载支持        
          if (is_dir(VENDOR_PATH . 'composer')) {            self::registerComposerLoader();        
          }        // 自动加载extend目录        
          self::$fallbackDirsPsr4[] = rtrim(EXTEND_PATH, DS);    
  }



从过控制器和方法名的转换,解析url中的参数,最终实例出APP的类,调用invokefunction方法。
其中Loader::parseName($controller, 1)方法,这个可以控制这种直接传递命名空间的参数,

 /** 
     * 字符串命名风格转换     
     * type 0 将Java风格转换为C的风格 1 将C风格转换为Java的风格     
     * @param string  $name 字符串     
     * @param integer $type 转换类型     
     * @param bool    $ucfirst 首字母是否大写(驼峰规则)     
     * @return string     
     */    
    public static function parseName($name, $type = 0, $ucfirst = true)
{        if ($type) {      
             $name = preg_replace_callback('/_([a-zA-Z])/', function ($match) {                return strtoupper($match[1]);         
             }, $name);            return $ucfirst ? ucfirst($name) : lcfirst($name);        
         } else {            return strtolower(trim(preg_replace("/[A-Z]/", "_\0", $name), "_"));     
         }    
    }

方法中只匹配了/_([a-zA-Z])/的正则,反斜线过滤掉,就可以防止这种rce的执行。看一下官方的处理方式:




它这种就是检验这种直接传递命名空间违规的方式,给过滤掉。加载位置:



再请求出现了正确的拦截:



这里编号CNVD-2021-65112漏洞复现完成。

总结

记录几个RCE的涉及函数吧,积累后续挖掘的突破口,希望大家来补充!

  • array_walk_recursive

  • call_user_func

  • call_user_func_array

  • array_map()

  • preg_replace

  • array_filter()
    还有很多,,,常遇到频率比较高的应该是前四个,没有具体统计。感兴趣的小伙伴,可以关注TIDE安全团队,看下

    代码审计wiki,代码执行漏洞篇
  • http://wiki.tidesec.com/docs/codeaudit/3d336f68c2686b738d86cd65e479173f



E

N

D


本文作者:TideSec

本文为安全脉搏专栏作者发布,转载请注明:https://www.secpulse.com/archives/182005.html

Tags:
评论  (0)
快来写下你的想法吧!

TideSec

文章数:145 积分: 185

安全问答社区

安全问答社区

脉搏官方公众号

脉搏公众号