TEXTCUBE鸡肋读取文件漏洞 顺便求突破
韩国的一个博客程序TEXTCUBE 读了下发现个奇怪的问题 技术有限 希望大家点拨下!
\framework\Dispatcher.php (57行)
$part = strtok($uri['input'], '/'); // $uri['input'] == resources/locale/messages.php.
if (in_array($part, array('resources','plugins','cache','skin','attach','thumbnail'))) { //限制了读取目录 无法直接读根目录
$part = ltrim(rtrim($part == 'thumbnail' ?
preg_replace('/thumbnail/', 'cache/thumbnail', $uri['input'], 1) :
$uri['input']), '/');
$part = (($qpos = strpos($part, '?')) !== false) ? substr($part, 0, $qpos) : $part;
if(file_exists($part)) {
require_once ROOT.'/library/function/file.php';
dumpWithEtag($part); //读取
exit;
} else {
header("HTTP/1.0 404 Not Found");exit;
}
}
function dumpWithEtag($path) {
$path = urldecode($path);
$qIndex = strpos($path,'?');
if( $qIndex !== false ) {
$path = substr($path,0,$qIndex);
}
/* I think, it is a bad idea to check '..' and skip.
but this is an annoyance to solve gracefully about whole HTTP request */
/* Kill them all requests with referencing parent directory */
if( strpos( $path, "/.." ) !== false ||
strpos( $path, "\\.." ) !== false || //卡在此处
strcasecmp( substr( $path, -3 ), "php" ) == 0 ||
!file_exists( $path ) ) {
header("HTTP/1.0 404 Not found");
exit;
}
$fs = stat( $path );
if( !$fs || !$fs['size'] ) { header('HTTP/1.1 404 Not Found');exit; }
$etag = sprintf( "textcube-%x", (0x1234*$fs['size'])^$fs['mtime'] );
$lastmodified = gmdate("D, j M Y H:i:s ", $fs['mtime']) . "GMT";
$length = $fs['size'];
if( !headerEtag($etag,$length,$lastmodified) ) {
//echo $path;
//exit;
header('Content-type: '.getMIMEType(null,$path));
$f = fopen($path,"r");
if( !$f ) {
header("HTTP/1.0 404 Not found");
exit;
}
while( ($content=fread($f,8192)) ){
echo $content;
}
fclose($f);
}
}
测试环境是windows7+apache2.0+php5.2.14 由于是windows下 所以可以绕过strcasecmp( substr( $path, -3 ), "php" ) 这句的限制 直接在php后面加个点即可
下面问题来了, 程序中限制了读取文件的几个目录 array('resources','plugins','cache','skin','attach','thumbnail') 所以要读取根目录的config肯定得跳到上层的
而dumpWithEtag函数里总共有3个过滤 分别是 /.. \\.. 以及后缀是否为php
看样子很白痴的一个验证 很轻松就能绕过的 因为/..可以用\..替换 \\..更是不用说了 , 所以构造了以下格式
http://127.0.0.1/tc/index.php?resources/\..\config.php.
因为最开头有一句$part = strtok($uri['input'], '/') 用来获取目录 所以在白名单目录后必须有一个/号 这格式看似是没问题的吧
但是却卡在了strpos( $path, "\\.." ) !== false 这里 百思不得其解
随后分别用了以下格式:
http://127.0.0.1/tc/index.php?resources/.\..\config.php.
http://127.0.0.1/tc/index.php?resources/1212\..\..\config.php.
通通都卡在那一句了 明明没出现\\..字符串的 为何不行呢?
评论19次
在双引号 “” 里, \\ 就是 \所以这句 "\\.." 就是争对 \.. 而写
最后解决方式是什么?对于19楼的方法求鉴定。
\:..\ 环境变量切换:直接切换至根目录貌似linux win 通用 还有过滤方式不是正则 没有重复判断 .../.../目录../这样也是可以的吧
支持大牛继续深挖洞,广积棒
都挖到国外去了。加油挖。
棒子又要遭殃呢
药药、切脑壳!
给力。LZ就是大牛的料啊
腻害腻害,多挖几个棒子帅哥吧
努力学xi中
又见端屎啊。
都挖到国外去了。加油挖。
哈哈哈``看来看代码看到头晕了``
棒子要悲哀 挖牛 可劲挖
棒子又躺着中枪
棒子,又要遭殃了。
支持挖洞牛啊
...暗藏玄机..支持挖洞牛.
我晕 明白了 忘了这岔了 一语道破啊
在双引号 “” 里, \\ 就是 \ 所以这句 "\\.." 就是争对 \.. 而写