filter_var函数缺陷(原理+实践)

函数缺陷原理

先看一段代码

这段代码的逻辑大概是这个样子:

这个代码的类中有render()方法,其中render方法在index.html网页上输出了一个链接,这个过程是通过模板实现的,模板首先通过了escape方法进行过滤,其中链接的参数是通过getNexSlideUrl()获得的,往上看这个函数,这个函数是通过get方法获得一个参数然后通过filter_var()函数进行过滤作为函数的返回值。

escape方法

其中escape方法的原理是用htmlspecialchars()实现的

htmlspecialchars  :(PHP 4, PHP 5, PHP 7)

功能 :将特殊字符转换为 HTML 实体

定义 :string htmlspecialchars ( string $string [, int $flags = ENT_COMPAT | ENT_HTML401 [, string$encoding = ini_get("default_charset") [, bool $double_encode = TRUE ]]] )

& (& 符号)  ===============  &
" (双引号)  ===============  "
' (单引号)  ===============  '
< (小于号)  ===============  &lt;
> (大于号)  ===============  &gt;

filter_var 函数

filter_var 函数来过滤 nextSlide 变量,且用了 FILTER_VALIDATE_URL 过滤器来判断是否是一个合法的url,具体的 filter_var 定义如下:

filter_var : (PHP 5 >= 5.2.0, PHP 7)

功能 :使用特定的过滤器过滤一个变量

定义mixed filter_var ( mixed $variable [, int $filter = FILTER_DEFAULT [, mixed $options ]] )

demo

为了能更清晰的看清楚代码逻辑,下面写一个demo

<?php
$url = filter_var($_GET['url'],FILTER_VALIDATE_URL);
var_dump($url);
echo "<br>";
$url = htmlspecialchars($url);
//$url=urldecode($url);
var_dump($url);
echo "<br>";
//$url=urldecode($url);
echo "<a href='$url'>Next slide</a>";
?>

那么针对这两个函数的过滤我们采用JavaScript伪协议进行绕过

payload:

?url=javascript://comment%250aalert(1)

其中//在javascrpt里面是换行符,url传入后端的时候会被第一次url解码,此时%25被解码成%,和后面0a拼接成%0a,当点击链接的时候,会进行第二次url解码,其中%0a会被解码成换行符,alert(1)就被换到了下一行,逃过了注释符号,也被浏览器解析。

实战利用

环境搭建:Anchor 0.9.2

 在该版本中,当用户访问一个不存在的URL链接时,程序会调用404模板,而这个模板则存在XSS漏洞,具体代码如下:

//anchor-cms-0.9.2\themes\default\404.php
<?php theme_include('header'); ?>

	<section class="content wrap">
		<h1>Page not found</h1>

		<p>Unfortunately, the page <code>/<?php echo current_url(); ?></code> could not be found. Your best bet is either to try the <a href="<?php echo base_url(); ?>">homepage</a>, try <a href="#search">searching</a>, or go and cry in a corner (although I don’t recommend the latter).</p>
	</section>

<?php theme_include('footer'); ?>

然后跟进一下current_url()函数

//anchor-cms-0.9.2\anchor\functions\helpers.php
function current_url() {
	return Uri::current();
}

然后跟进一下Uri类的current()函数

//anchor-cms-0.9.2\system\uri.php
class Uri {

	public static function current() {
		if(is_null(static::$current)) static::$current = static::detect();

		return static::$current;
	}

}

 然后跟进一下detect()函数

	public static function detect() {
		// create a server object from global
		$server = new Server($_SERVER);

		$try = array('REQUEST_URI', 'PATH_INFO', 'ORIG_PATH_INFO');

		foreach($try as $method) {

			// make sure the server var exists and is not empty
			if($server->has($method) and $uri = $server->get($method)) {

				// apply a string filter and make sure we still have somthing left
				if($uri = filter_var($uri, FILTER_SANITIZE_URL)) {

					// make sure the uri is not malformed and return the pathname
					if($uri = parse_url($uri, PHP_URL_PATH)) {
						return static::format($uri, $server);
					}

					// woah jackie, we found a bad'n
					throw new ErrorException('Malformed URI');
				}
			}
		}

		throw new OverflowException('Uri was not detected. Make sure the REQUEST_URI is set.');
	}

该方法会获取 $_SERVER 数组中的 'REQUEST_URI' 、'PATH_INFO', 、'ORIG_PATH_INFO' 三个键的值(下图第3-4行代码),如果存在其中的某一个键,并且符合 filter_var($uri, FILTER_SANITIZE_URL)parse_url($uri, PHP_URL_PATH) ,则直接将 $uri 传入 static::format 方法。

$_SERVER["REQUEST_URI"]函数

预定义服务器变量的一种,所有$_SERVER开头的都叫做预定义服务器变量 REQUEST_URI的作用是取得当前URI,也就是除域名外后面的完整的地址路径

例如。当前页面是http://www.zixueku.com/plus/search.php?kwtype=0&keyword=php&searchtype=titlekeyword

echo $_SERVER["REQUEST_URI"];

结果就为:plus/search.php?kwtype=0&keyword=php&searchtype=titlekeyword

$_SERVER["PATH_INFO"]函数

http://www.test.com/index.php/foo/bar.html?c=index&m=search
我们可以得到 $_SERVER['PATH_INFO'] = ‘/foo/bar.html’

跟进format方法

public static function format($uri, $server) {
		// Remove all characters except letters,
		// digits and $-_.+!*'(),{}|\\^~[]`<>#%";/?:@&=.
		$uri = filter_var(rawurldecode($uri), FILTER_SANITIZE_URL);

		// remove script path/name
		$uri = static::remove_script_name($uri, $server);

		// remove the relative uri
		$uri = static::remove_relative_uri($uri);

		// return argument if not empty or return a single slash
		return trim($uri, '/') ?: '/';
	}

过滤函数解释 

rawurldecode函数

(PHP 4, PHP 5, PHP 7, PHP 8)

rawurldecode — 对已编码的 URL 字符串进行解码

说明

rawurldecode(string $str): string

返回字符串,此字符串中百分号(%)后跟两位十六进制数的序列都将被替换成原义字符。

	public static function remove($value, $uri) {
		// make sure our search value is a non-empty string
		if(is_string($value) and strlen($value)) {
			// if the search value is at the start sub it out
			if(strpos($uri, $value) === 0) {
				$uri = substr($uri, strlen($value));
			}
		}

		return $uri;
	}


	public static function remove_script_name($uri, $server) {
		return static::remove($server->get('SCRIPT_NAME'), $uri);
	}

	/
	public static function remove_relative_uri($uri) {
		// remove base url
		if($base = Config::app('url')) {
			$uri = static::remove(rtrim($base, '/'), $uri);
		}

		// remove index
		if($index = Config::app('index')) {
			$uri = static::remove('/' . $index, $uri);
		}

		return $uri;
	}

没有针对XSS攻击进行过滤,导致攻击十分容易,我们来看看XSS攻击具体是如何进行的。 


http://localhost/anchor/index.php/<script>alert('www.sec-redclub.com')</script> 。根据上面的分析,当我们访问这个并不存在的链接时,程序会调用404模板页面,然后调用 current_url 函数来获取当前用户访问的文件名,也就是最后一个 / 符号后面的内容,所以最终payload里的 <script>alert('www.sec-redclub.com')</script> 部分会嵌入到 <code> 标签中,造成XSS攻击

filter_var函数缺陷(CTF例题,附源码)

参考资料

先知社区-红日团队 

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值