xss初试

xss

反射型 js处理返回后端后又反馈回前端
存储型 储存到某一介质中
DOM型 直接有js解析后反馈给前端

xss漏洞的修复办法

HTML实体编码
使用白名单过滤掉用户输入的恶意字符
根据业务场景对症下药
对关键的cookie使用http-only

存储型xss

攻击者在页面上插入XSS代码,服务端将数据存入数据库,当用户访问到存在XSS漏洞的页面时,服务端从数据库中取出数据展示到页面上,导致XSS代码执行,达到攻击效果。

漏洞挖掘

存在输入点就可能存在xss
存在输入点并保存在后端且可以查看
<img scr=1 οnerrοr=alert(document.cookie)>获取cookie

漏洞修复

php : 添加strip_tag函数 剥去字符串中的 HTML 标签:可防止html注入
暴力方法,在文本框中可能需要HTML的操作例如<b> <h1>需要加粗或其他就不适用了
addslashes() 函数返回在预定义字符之前添加反斜杠的字符串。
stripslashes() 函数 删除反斜杠

DVWA 例子

low

直接script
看看php
首先trim函数去空格只去除头尾
然后stripslashes删除反斜杠 isert 和is_object 判断变量是否存在和是否为对象
mysqli_real_escape_string 转义 SQL 语句中使用的字符串中的特殊字符
trigger_error对字长限制
mysqli_query() 函数执行某个针对数据库的查询
mysqli_error() 函数返回最近调用函数的最后一个错误描述。

<?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();
}
?>

medium

php
首先两个trim去空格
然后strip_tag剥离HTML标签
mysqli_real_escape_string转义SQL
trigger_error限字数
难道就没有办法了吗,不是还有name吗,直接修改maxlength=100 这样子就够写了
依旧是简单的script


<?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();
}

?>

HIGH

修改name长度简简单单img加onerror
加了个preg_replace函数可以写正则表达式


<?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();
}

?>

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();

?>

反射型xss

攻击者在URL中插入XSS代码,服务端将URL中的XSS代码输出到页面上,攻击者将带有XSS代码的URL发送给用户,用户打开后受到XSS攻击。

漏洞挖掘

URL传参数
atuofocus οnfοcus=alert(1)
javascript:alert(1)

修复

过滤 & (和号)&amp " (双引号)&quot’ (单引号)< (小于)&lt> (大于)&gt
htmlspecialchars 把预定义的字符 “<” (小于)和 “>” (大于)转换为 HTML 实体
如需把特殊的 HTML 实体转换回字符,请使用 htmlspecialchars_decode() 函数,可能会被利用

DVWA 例子

low

很简单直接script就可以,看看php
将get的name直接输出

<?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>';
}
?>

medium

依然很简单,script输入发现alert(1)输出了,所以应该是script被过滤了所以用img 加onerror就可以了
看看php
str_replace() 函数替换字符script为空,因为这个函数区分大小写所以可以用大写绕过,
还可以用双显绕过

<?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
    echo "<pre>Hello ${name}</pre>";
}
?>

HIGH

还是输入script试试结果只输出> 又试了试< 发现可以输出,难道又是script屏蔽
还是老套路img 加onerror
看看php
真的是script屏蔽只是更加严格不能用大写绕过也不能用双写绕过
preg_replace 函数执行一个正则表达式的搜索和替换。

<?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
    echo "<pre>Hello ${name}</pre>";
}
?>
正则表达式

#一个’.‘就是匹配\n(换行符)以外的任何字符
‘a.b’ eg :acb
#一个’*‘前面的字符出现0次或以上
‘a*b’ eg:acdb
#贪婪,匹配从.*前面为开始到后面为结束的所有内容。
‘a.*b’
#非贪婪,遇到开始和结束就截取,因此截取多次符合的结果,中间没有字符也会被截取 ???
‘a.*?b’
#非贪婪,与上面是一样的,只是与上面相比,多了一个括号,只保留括号中的内容
‘a(.*?)b’
//不要在意出现这么奇怪的内容,这是python的正则表达式 import re
#re.S不会对\n进行中断
print(re.findall(r’a(.*?)b’,str,re.S))
#保留a,b中间的内容
print(re.findall(r’a(.+?)b’,str))
print(re.findall(r’a(.+?)b’,str)[0])

Impossible

htmlspecialchars()函数转化为HTML实体编码
话说这个难度为什么是默认选项


<?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
    echo "<pre>Hello ${name}</pre>";
}

// Generate Anti-CSRF token
generateSessionToken();

?>

DOMxss

攻击者在URL中插入XSS代码,前端页面直接从URL中获取XSS代码并且输出到页面,导致XSS代码的执行,攻击者将带有XSS代码的URL发送给用户,用户打开后受到XSS攻击。
感觉和其他的没什么区别
注意观察HTML存在的注入点

修复

text

DVWA eg

low

script直接搞定
看php
什么都没有

<?php
# No protections, anything goes
?>

medium

看HTML发现注入点在select里面的option中所以将option和select标签全部屏蔽加入alert就好了
</option></select><img src=# οnerrοr=alert(1)>
看php
array_key_exists() 函数检查某个数组中是否存在指定的键名,如果键名存在则返回 true,如果键名不存在则返回 false。
stripos() 函数查找字符串在另一字符串中第一次出现的位置(不区分大小写)。还是对script管控

<?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;
    }
}

?>

HIGH

tip:URL中#号之后的内容,不会被提交到服务器,可以直接与浏览器进行交互
所以直接#<script>alert(1)</script>
看php
这里使用了白名单过滤

<?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;
    }
}
?>

impossible

没有php但是用了URL编码对 < 和>进行限制
下面是w3schoolURL编码的网站

https://www.w3school.com.cn/tags/html_ref_urlencode.html

攻击语句

<script>location=“https://www.baidu.com”</script> //页面跳转
<iframe src= httpss:www.baidu.com width=400 height=300></iframe> //嵌入页面
<iframe src= httpss:www.baidu.com width=0 height=0 frameborder></iframe>
<img scr=1 οnerrοr=alert(document.cookie)>获取cookie

绕过

<img scr=1 οnerrοr=alert(document.cookie)>
双显绕过
<scr<script>ipt>alert(1)</scr</script>ipt>
大小写绕过(php不区分大小写)
<ScRiPt>alert(1)</ScRiPt>
突破alert
<script>confirm(‘hack’)</script>
<img src=1 οnerrοr=confirm(‘1’)>

"><iframe src=javascript:alert(1)>
"><a href=javascript:alert(1)>
"> <a href=“javascript:alert(1)”>123</a>
"> <a href=“javascript:%61lert(1)”>123</a> //
tip:URL中#号之后的内容,不会被提交到服务器,可以直接与浏览器进行交互
绕过尖括弧 通过u003c和u003e来代
u003cimg src=1 οnerrοr=alert(/xss/)u003e
’ οnmοuseοver= alert(1)
" οnclick=alert(1)

JavaScript等过滤字符的绕过

HTML字符实体转换
javascript:alert(1)
javascript:alert1
javascript:alert1

隐藏的输入框:

hidden
keyword = test&t_sort="type=“text” οnmοuseοver="alert(1)

http头部的xss注入

burp抓包,改Referer头

php修复函数

strip_tag函数 剥去字符串中的 HTML 标签:可防止html注入
addslashes() 函数返回在预定义字符之前添加反斜杠的字符串。
stripslashes() 函数 删除反斜杠
trim函数去空格只去除头尾
str_replace() 函数替换字符
preg_replace 函数执行一个正则表达式的搜索和替换。
htmlspecialchars() 函数转化为HTML实体编码
array_key_exists() 函数检查某个数组中是否存在指定的键名,如果键名存在则返回 true,如果键名不存在则返回 false。使用白名单过滤
stripos() 函数查找字符串在另一字符串中第一次出现的位置(不区分大小写)

remove_xss 这个之后再研究

https://www.jb51.net/article/70238.htm

function remove_xss($val) {
  // remove all non-printable characters. CR(0a) and LF(0b) and TAB(9) are allowed
  // this prevents some character re-spacing such as <java\0script>
  // note that you have to handle splits with \n, \r, and \t later since they *are* allowed in some inputs
  $val = preg_replace('/([\x00-\x08,\x0b-\x0c,\x0e-\x19])/', '', $val);
  // straight replacements, the user should never need these since they're normal characters
  // this prevents like <IMG SRC=@avascript:alert('XSS')>
  $search = 'abcdefghijklmnopqrstuvwxyz';
  $search .= 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
  $search .= '1234567890!@#$%^&*()';
  $search .= '~`";:?+/={}[]-_|\'\\';
  for ($i = 0; $i < strlen($search); $i++) {
   // ;? matches the ;, which is optional
   // 0{0,7} matches any padded zeros, which are optional and go up to 8 chars
   // @ @ search for the hex values
   $val = preg_replace('/(&#[xX]0{0,8}'.dechex(ord($search[$i])).';?)/i', $search[$i], $val); // with a ;
   // @ @ 0{0,7} matches '0' zero to seven times
   $val = preg_replace('/(�{0,8}'.ord($search[$i]).';?)/', $search[$i], $val); // with a ;
  }
  // now the only remaining whitespace attacks are \t, \n, and \r
  $ra1 = array('javascript', 'vbscript', 'expression', 'applet', 'meta', 'xml', 'blink', 'link', 'style', 'script', 'embed', 'object', 'iframe', 'frame', 'frameset', 'ilayer', 'layer', 'bgsound', 'title', 'base');
  $ra2 = array('onabort', 'onactivate', 'onafterprint', 'onafterupdate', 'onbeforeactivate', 'onbeforecopy', 'onbeforecut', 'onbeforedeactivate', 'onbeforeeditfocus', 'onbeforepaste', 'onbeforeprint', 'onbeforeunload', 'onbeforeupdate', 'onblur', 'onbounce', 'oncellchange', 'onchange', 'onclick', 'oncontextmenu', 'oncontrolselect', 'oncopy', 'oncut', 'ondataavailable', 'ondatasetchanged', 'ondatasetcomplete', 'ondblclick', 'ondeactivate', 'ondrag', 'ondragend', 'ondragenter', 'ondragleave', 'ondragover', 'ondragstart', 'ondrop', 'onerror', 'onerrorupdate', 'onfilterchange', 'onfinish', 'onfocus', 'onfocusin', 'onfocusout', 'onhelp', 'onkeydown', 'onkeypress', 'onkeyup', 'onlayoutcomplete', 'onload', 'onlosecapture', 'onmousedown', 'onmouseenter', 'onmouseleave', 'onmousemove', 'onmouseout', 'onmouseover', 'onmouseup', 'onmousewheel', 'onmove', 'onmoveend', 'onmovestart', 'onpaste', 'onpropertychange', 'onreadystatechange', 'onreset', 'onresize', 'onresizeend', 'onresizestart', 'onrowenter', 'onrowexit', 'onrowsdelete', 'onrowsinserted', 'onscroll', 'onselect', 'onselectionchange', 'onselectstart', 'onstart', 'onstop', 'onsubmit', 'onunload');
  $ra = array_merge($ra1, $ra2);
  $found = true; // keep replacing as long as the previous round replaced something
  while ($found == true) {
   $val_before = $val;
   for ($i = 0; $i < sizeof($ra); $i++) {
     $pattern = '/';
     for ($j = 0; $j < strlen($ra[$i]); $j++) {
      if ($j > 0) {
        $pattern .= '(';
        $pattern .= '(&#[xX]0{0,8}([9ab]);)';
        $pattern .= '|';
        $pattern .= '|(�{0,8}([9|10|13]);)';
        $pattern .= ')*';
      }
      $pattern .= $ra[$i][$j];
     }
     $pattern .= '/i';
     $replacement = substr($ra[$i], 0, 2).'<x>'.substr($ra[$i], 2); // add in <> to nerf the tag
     $val = preg_replace($pattern, $replacement, $val); // filter out the hex tags
     if ($val_before == $val) {
      // no replacements were made, so exit the loop
      $found = false;
     }
   }
  }
  return $val;
}

$ra1 对HTML标签做限制
$ra2 对js事件做限制
排查风险
array_merge() 函数把一个或多个数组合并为一个数组。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值