目录穿越漏洞修复之后再利用
2019-11-18 22:09:00 Author: mp.weixin.qq.com(查看原文) 阅读量:82 收藏

本文作者:Z1NG(信安之路 2019 年度优秀作者)

前段时间看到安全狗海青实验室发的一篇关于压缩文件解压导致 getshell 的文章。其中一个漏洞是在 zzzcms1.73 版本。而这款 CMS 自己也算是审过几次,虽然小众,但的确是学习审计的好例子~

安全狗的文章中介绍了 zzzcms 的后台由于上传时存在目录穿越,可以上传到任意路径下,再配合后台解压的功能,就完成了 webshell 的植入。有意思的是,上传功能做了相对严格的后缀检测,而解压功能也只能解压指定文件夹里的压缩包文件,两个功能其实各自都不存在什么大问题,而却因为目录穿越问题导致两个功能点串联在一起,从而完成了 getshell。具体细节可以去看看原文《文件解压引发的 getshell》

目录穿越的助攻

在 zzzcms 的官网上看到做了更新,并且修补了上面提到的漏洞。

下载了最新版的源码,试图绕过修补。然鹅,在尝试数次后,无果。于是,转而看看其他代码。因为之前出现过目录穿越的问题,那么很可能在其他也存在相同的问题。简单翻阅以后,看到如下代码。

很显然,在 69 行我们可以控制一个变量,而这个变量参与了一个路径的构造,因此我们可以控制这个路径跳转到任意目录。而在 78 行处调用了 simplexml_load_file 进行解析 XML,而并没有禁用引用外部实体,所以如果控制了 plug.xml 里的内容,就可以造成一个 XXE 漏洞。

为了控制 plug.xml 文件的内容,需要找到上传功能处。有意思的是,尽管上传功能的目录穿越已经被修补了无法利用,但是这里却存在目录穿越的问题,所以只要上传一个 plug.xml 文件,再控制解析 XML 文件的路径即可完成 XXE。而大多数的上传文件功能都会把文件进行重命名,找到上传功能的代码,如下:

function upload( $file, $type, $folder, $format = NULL, $max_width = NULL, $max_height = NULL ) {  if ( isset( $file ) ) {    $files = $file;  } elseif ( !isset( $_FILES[ $file ] ) ) {      $files = $_FILES[ $file ];    } else {      return array();    }    // 定义允许上传的扩展  if ( !isset( $type ) ) {    return array( 'state' => '上传类型不能为空' );  } else {    switch ( $type ) {      case 'file':        $array_ext_allow = explode( ',', Conf( 'fileext' ) );        $format = Conf( 'fileformat' );        break;      case 'video':        $array_ext_allow = explode( ',', Conf( 'videoext' ) );        $format = Conf( 'videoformat' );        break;      case 'image':        $array_ext_allow = explode( ',', Conf( 'imageext' ) );        $format = Conf( 'imageformat' );        break;      default:        $array_ext_allow = explode( ',', strtolower( $type ) );        break;    }  }  if ( !$files[ 'error' ] ) {    $upfile = $files[ 'name' ];    $file_arr = explode( '.', $upfile );    $file_ext = safe_word(strtolower( end( $file_arr )),'4');            $file_name = str_replace( '.' . end( $file_arr ), '', $upfile );        if(empty($file_ext)) {            return array( 'state' => '上传类型不能为空!' );        }elseif ( in_array( $file_ext, array('php','asp','aspx','exe','sh','sql','bat') ) ) {      return array( 'state' => $file_ext.'格式的文件不允许上传,请重新选择!' );    } elseif ( !in_array( $file_ext, $array_ext_allow ) ) {      var_dump($file_ext);      return array( 'state' => $file_ext . '格式的文件不能上传,请重新选择!');    }    $savefile = array( 'state' => 'SUCCESS', 'ext' => $file_ext, 'title' => $file_name, 'url' => handle_upload( $files[ 'name' ], $files[ 'tmp_name' ], $array_ext_allow, $folder, $format, $file_name, $file_ext, $max_width, $max_height ) );    return $savefile;  } else {    return $files[ 'error' ];  }}

上面的 代码看到用黑名单限制了后缀名,显然这个黑名单是不严格的,随意上传 php5 这类后缀。检查完后缀之后就来到了 handle_upload 函数,这个函数的主要功能就是将文件进行保存。代码如下:

function handle_upload( $file, $temp, $array_ext_allow, $folder, $format, $file_name, $file_ext, $max_width, $max_height ) {  // 检查文件存储路径  if ( conf( 'datefolder' ) == 1 ) {    $save_path = SITE_DIR . conf( 'uploadpath' ) . $folder . '/' . date( 'Ymd' );    check_dir( $save_path, true );  } else {    $save_path = SITE_DIR . conf( 'uploadpath' ) . $folder;    check_dir( $save_path, true );  }  if ( $format == 'pinyin' ) {    $newname = pinyin( $file_name );  } elseif ( $format == 'yuanming' ) {    $newname = toutf( $file_name );  } else {    $newname = time() . mt_rand( 100000, 999999 );  }  $file_path = $save_path . '/' . $newname . '.' . $file_ext;  if ( is_file( $file_path ) ) {    if ( conf( 'covermark' ) == 1 ) {      del_file( $file_path );    } else {      $file_path = $save_path . '/' . $newname . mt_rand( 1000, 9999 ) . '.' . $file_ext;    }  }  move_uploaded_file( $temp, $file_path ); // 从缓存中转存    $save_file = str_replace( SITE_DIR, SITE_PATH, $file_path );  if ( $format == 'yuanming' )$save_file = togbk( $save_file );  // 如果是图片进行等比例缩放  if ( is_image( $file_path )) {    resize_img( $file_path, $file_path, 0, Conf( 'compresswidth' ), Conf( 'compressheight' ),Conf( 'compressquality') );  }  return $save_file;}

文件名是否随机取决于变量 $format,当 $format 的值为 pinyin 时,则就保存为原文件名。因此,已经可以通过上传一个 plug.xml 来控制 XML 解析的内容。

利用

为了方便验证漏洞,在 C 盘下建立一个目标文件,内容如下。

利用漏洞:

首先先准备一个 plug.xml 文件用于上传。

然后准备一个 a.dtd 文件,放在可控服务器的 web 目录下,

然后编写一个上传页面,

将文件上传

然后触发 XXE 漏洞

POST:

http://127.0.0.1/zzzphp/admin/save.php?act=plugkeyplugpath=../upload/file&plugkey=e10adc3949ba59abbe56e057f20f883e

查看 web 日志,可以发现 flag.txt 的内容被携带的传送到了服务器上。

最后

目录穿越其实只是个小问题,有种打辅助的感觉。就像这个漏洞,如果禁用了外部实体,同样也不能进行 XXE,不过也正是因为目录穿越,这个 XXE 才可以被利用。一直以来分享的文章都很基础很简单,充其量只是个入门的水平,让各位大佬见笑了。:)


文章来源: http://mp.weixin.qq.com/s?__biz=MzI5MDQ2NjExOQ==&mid=2247491870&idx=1&sn=74a6f0e427919d5603ead3a3277adb1c&chksm=ec1dd136db6a5820a48725653c9b1939b7ebfa9c81373545c456578a5403d836acfc7783f080#rd
如有侵权请联系:admin#unsafe.sh