### 简要描述: 一个二次操作造成的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的值。这个实际上是相册封面的意思。...
### 简要描述: 一个二次操作造成的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 $appapp名称 * @param unknown $w缩略图片宽度 * @param unknown $h缩略图片高度 * @param string $path * @param string $c1裁切,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);">](https://images.seebug.org/upload/201408/12143152b794bb997e6814da0f8cb64a76b6bdf6.jpg) 记下这个时候的专辑id,我的是1: [<img src="https://images.seebug.org/upload/201408/12144454cc319ae6d4280f5808b7dec4ce79acaa.jpg" alt="002.jpg" width="600" onerror="javascript:errimg(this);">](https://images.seebug.org/upload/201408/12144454cc319ae6d4280f5808b7dec4ce79acaa.jpg) 把shell改后缀为.gif然后上传。注意,不需要用图片木马,直接webshell上传即可。因为后面要验证图片的宽度小于170,如果你的图片木马太大反而不能生成。 查看,并记下路径: [<img src="https://images.seebug.org/upload/201408/121445152a3c445dc45ecc09cd32fd499c918e42.jpg" alt="003.jpg" width="600" onerror="javascript:errimg(this);">](https://images.seebug.org/upload/201408/121445152a3c445dc45ecc09cd32fd499c918e42.jpg) 然后向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);">](https://images.seebug.org/upload/201408/121445410e16aad50558c8c0f811fac6df0786ce.jpg) 如上图,我们之前说的$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);">](https://images.seebug.org/upload/201408/1214481033d3a8c72dab2f819eded037b568c41a.jpg) 查看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);">](https://images.seebug.org/upload/201408/12144829ad46813639773d0a7d89b55b6efb665b.jpg) 所以说这是一个“二次getshell”,先让危险的数据进入数据库,再通过程序取出,getshell。