ThinkSAAS前台Getshell

2014-08-12T00:00:00
ID SSV:94328
Type seebug
Reporter Root
Modified 2014-08-12T00:00:00

Description

简要描述:

一个二次操作造成的getshell。 官网又挂加速乐,又审核什么的,懒得测试官网了,就麻烦审核大人本地测试拉~

详细说明:

说一下原理吧。 /app/photo/action/album.php 245行

``` //批量修改执行 case "info_do":

    //用户是否登录
    $userid = aac('user')->isLogin();

    $albumid = intval($_POST['albumid']);

    $albumface = tsClean($_POST['albumface']);

    $arrPhotoId = $_POST['photoid'];
    $arrPhotoDesc = $_POST['photodesc'];

    if($TS_USER['user']['isadmin']==0){

        foreach($arrPhotoDesc as $key=>$item){

            //过滤内容开始
            aac('system')->antiWord($item);
            //过滤内容结束

        }
    }

    foreach($arrPhotoDesc as $key=>$item){
        if($item){
            $photoid = intval($arrPhotoId[$key]);

            $new['photo']->update('photo',array(
                'photoid'=>$photoid,
            ),array(

                'photodesc'=>tsClean($item),

            ));

        }
    }

    //更新相册封面
    if($albumface){
        $new['photo']->update('photo_album',array(
            'userid'=>$userid,
            'albumid'=>$albumid,
        ),array(
            'albumface'=>$albumface,
        ));
    }

    header("Location: ".tsUrl('photo','album',array('id'=>$albumid)));

    break;

```

观察这个动作:$albumface = tsClean($_POST['albumface']); 从POST albumface获得了albumface的值。这个实际上是相册封面的意思。 tsClean是过滤xss的函数,跟本操作无关,暂且不表。 获得了albumface后插入photo_album表:

//更新相册封面 if($albumface){ $new['photo']->update('photo_album',array( 'userid'=>$userid, 'albumid'=>$albumid, ),array( 'albumface'=>$albumface, )); }

本来是无害的一个操作。不过我们再来看到另一个位置(安装好以后才有的)。 /cache/template/photo.photo.tpl.php:

<div><a href="<?php echo tsurl('photo','album',array('id'=>$item['albumid']))?>" class="album_photo"><img src="<?php if($item['albumface'] == '') { ?><?php echo SITE_URL;?>app/photo/skins/default/photo_album.png<?php } else { ?><?php echo tsXimg($item['albumface'],'photo',170,'170',$item['path'],1)?><?php } ?>" width="170" height="170" alt="<?php echo $item['albumname'];?>" /></a>

这里取到了$item['albumface'],并传入tsXimg函数。于是我们来看看这个函数: /thinksaas/tsFunction.php 671行

``` /* * ThinkSAAS专用图片截图函数 * @param unknown $file 数据库里的图片url * @param unknown $app app名称 * @param unknown $w 缩略图片宽度 * @param unknown $h 缩略图片高度 * @param string $path * @param string $c 1裁切,0不裁切 * @return void|string / function tsXimg($file, $app, $w, $h, $path = '', $c = '0') {

if (! $file) {
    return false;
}else{

    //$info = explode ( '.', $file );
    //$name = md10 ( $file ) . '_' . $w . '_' . $h . '.' . $info [1];

    $info = explode ( '/', $file );
    $name = $info [2];

    if ($path == '') {
        $cpath = 'cache/' . $app . '/' . $w . '/' . $name;
    } else {
        $cpath = 'cache/' . $app . '/' . $path . '/' . $w . '/' . $name;
    }

    if (! is_file ( $cpath )) {
        createFolders ( 'cache/' . $app . '/' . $path . '/' . $w );
        $dest = 'uploadfile/' . $app . '/' . $file;
        $arrImg = getimagesize ( $dest );
        if ($arrImg [0] <= $w) {
            copy ( $dest, $cpath );

        } else {
            require_once 'thinksaas/tsImage.php';
            $resizeimage = new tsImage ( "$dest", $w, $h, $c, "$cpath" );
        }
    }

    return SITE_URL . $cpath;

}

} ```

这个函数过程是这样: 1.$info = explode ( '/', $file ); 将传入的路径用/来分成数组 2.$name = $info [2]; name是数组的第三项。 3.$cpath = 'cache/' . $app . '/' . $path . '/' . $w . '/' . $name; 将cpath设置一下,可以看到,直接将name放进cpath里了。 4.如果cpath不是文件,就创建目录:createFolders ( 'cache/' . $app . '/' . $path . '/' . $w ); 5.getimagesize ( $dest ); 获得dest的大小,dest是'uploadfile/' . $app . '/' . $file,传入文件的路径,$file可控。 6.if ($arrImg [0] <= $w) {copy ( $dest, $cpath );} 如果获得的宽度($arrImg [0])小于预设值$w,则直接将dest复制到cpath。 发现什么了吗,copy这个操作的两个参数都是我们可以控制的。于是,我们就可以轻松地getshell。 具体操作步骤见漏洞证明。

漏洞证明:

首先注册用户,创建一个专辑:

<img src="https://images.seebug.org/upload/201408/12143152b794bb997e6814da0f8cb64a76b6bdf6.jpg" alt="01.jpg" width="600" onerror="javascript:errimg(this);">

记下这个时候的专辑id,我的是1:

<img src="https://images.seebug.org/upload/201408/12144454cc319ae6d4280f5808b7dec4ce79acaa.jpg" alt="002.jpg" width="600" onerror="javascript:errimg(this);">

把shell改后缀为.gif然后上传。注意,不需要用图片木马,直接webshell上传即可。因为后面要验证图片的宽度小于170,如果你的图片木马太大反而不能生成。 查看,并记下路径:

<img src="https://images.seebug.org/upload/201408/121445152a3c445dc45ecc09cd32fd499c918e42.jpg" alt="003.jpg" width="600" onerror="javascript:errimg(this);">

然后向localhost/think/index.php?app=photo&ac=album&ts=info_do POST如下数据:

<img src="https://images.seebug.org/upload/201408/121445410e16aad50558c8c0f811fac6df0786ce.jpg" alt="004.jpg" width="600" onerror="javascript:errimg(this);">

如上图,我们之前说的$name取得是$info[2],也就是用/分割后的第三个,所以我前面加了个1/2/shell.php这个时候取的$name既是shell.php。 然后后面我需要用../跳转到根目录下,再把刚才记下的路径放在后面(上图第二个红框),发包后数据库里就改好了。 再访问一下localhost/think/index.php?app=photo,生成shell.php:

<img src="https://images.seebug.org/upload/201408/1214481033d3a8c72dab2f819eded037b568c41a.jpg" alt="005.jpg" width="600" onerror="javascript:errimg(this);">

查看http://localhost/think/cache/photo/170/shell.php即可:

<img src="https://images.seebug.org/upload/201408/12144829ad46813639773d0a7d89b55b6efb665b.jpg" alt="006.jpg" width="600" onerror="javascript:errimg(this);">

所以说这是一个“二次getshell”,先让危险的数据进入数据库,再通过程序取出,getshell。