DVWA-XSS
XSS的中文名称叫跨站脚本,是WEB漏洞中比较常见的一种。
特点:就是可以将恶意HTML/JavaScript代码注入到受害用户浏览的网页上,从而达到劫持用户会话的目的。
XSS根据恶意脚本的传递方式可以分为3种,分别为反射型、存储型、DOM型,前面两种恶意脚本都会经过服务器端然后返回给客户端,而DOM型不用将恶意脚本传输到服务器在返回客户端。
XSS(DOM)
原理:
DOM型XSS就是基于DOM文档对象模型的。对于浏览器来说,DOM文档就是一份XML文档,当有了这个标准的技术之后,通过JavaScript就可以轻松的访问它们了。
XSS-Low
1.代码
2.页面测试:
没有对default参数进行任何过滤。
直接对default参数进行修改,构造XSS代码,
可以看到,我们的script脚本成功执行了
3.对页面进行元素查看,
XSS-Medium
1.代码
stripos() 函数
stripos(string,find,start)
查找字符串在另一字符串中第一次出现的位置(不区分大小写)。
代码先检查了default参数是否为空,如果不为空则将default等于获取到的default值。这里还使用了stripos 用于检测default值中是否有 <script ,如果有的话,则将 default=English,则过滤了 <script (不区分大小写)。
2.进行攻击
1) 使用img、body等标签,使用<img src=1 οnerrοr=(‘hack’)>
但是并没有弹窗,我们查看网页源代码,发现我们的语句被插入到了value值中,但是并没有插入到option标签的值中,所以img标签并没有发起任何作用。
我们得先闭合前面的标签,我们构造语句闭合option标签:
构造该链接:
语句并没有执行,再次查看源代码,语句中只有 > 被插入到了option标签的值中,因为</option闭合了option标签,所以img标签并没有插入
构造语句去闭合select标签,img标签就是独立的一条语句.
构造:
语句已经插入
XSS-High
1.代码
使用了switch()函数,在这里相当于白名单,只允许传 default值为English、French、German、Spanish 其中一个。
default=English#<img src="" οnerrοr=alert(/xss/)>
XSS-Impossible
1.代码
注释写的是保护的代码在客户端的里面
访问一下
发现页面并没有弹出任何东西,而且语言框内的值是我们输入的参数的经过URL编码后的数据。
查看元素和源代码,发现对输入的参数并没有进行URL解码,所以我们输入的任何参数都是经过URL编码,然后直接赋值给option标签。所以,就不存在XSS漏洞了。
XSS(Reflected)
反射型xss一般出现在URL参数中及网站搜索栏中,由于需要点击包含恶意代码的URL才可以触发,并且只能触发一次,所以也被称为“非持久性xss”
过程:攻击者在URL中插入xss代码,服务端将URL中的xss代码输出到页面上,攻击者将带有xss代码的url发送给用户,用户打开后受到xss攻击
XSS-low
代码判断了name参数是否为空,如果不为空的话就直接打印出来,并没有对name参数做任何的过滤和检查
构造脚本
执行脚本
我们的代码已经被插入到页面中了
XSS-Medium
1.代码
str_replace()(区分大小写)
<?php
echo str_replace("world","Peter","Hello world!");
?>
把字符串 “Hello world!” 中的字符 “world” 替换成 "Peter”
增加了对于~~<script>~~ 的过滤
(1)可以多写入一个~~<script>~~ ,把中间的~~<script>~~ 标签替换为空之后 <scri 与pt>重新组合一个~~<script>~~,成功执行代码。
(2)可以利用大小写来绕过过滤,如 <ScriPt>
(3)
可以构造别的标签 如<img src=0 οnerrοr=alter(/xss/)>(当src不成立时,触发onerror事件,执行alter(/xss/)
XSS-High
1.代码
pre_replace函数
执行一个正则表达式的搜索与替换。从<开始,匹配script字符以及穿插在script之间的各种字符组合(意思是只要有script这六个字符一起出现,可以不连续,都将匹配出来被替换成空字符),最后的i表示不区分大小写。
可以通过img、body等标签的事件或者iframe等标签的src注入恶意的代码
插入页面中
XSS-Impossible
1.代码
代码先判断name是否为空,不为空的话然后验证其token,来防范CSRF攻击。然后再用htmlspecialchars函数将name中的预定义字符转换成html实体。
htmlspecialchars函数
把预定义的字符 “<” (小于)和 “>” (大于)转换为 HTML 实体,即文本原样输出,防止浏览器将其作为HTML元素
函数预定义的字符是:
& (和号)成为 &
" (双引号)成为 "
’ (单引号)成为 ’
< (小于)成为 <
> (大于)成为 >
XSS(Stored)
存储型xss一般出现在网站留言板,评论处,个人资料处,等需要用户对网站写入数据的地方。因为存储型xss的脚本是存储在网页中,所以也可以说是“持久性xss”
过程:攻击者在界面插入xss代码,服务器将数据导入数据库,当用户访问到存在xss漏洞的页面时,服务器从数据库取出数据放在页面,导致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();
}
?>
stripslashes()函数:删除反斜杠
trim(string,charlist)函数:
移除字符串两侧的空白字符或其他预定义字符。预定义字符包括“\0”,“t”,“\n”,“\x0B”,“\r”,“ ”
可选参数charlist支持添加额外需要删除的字符。
mysqli_real_escape_string(connection,escapestring)函数 :
转义在 SQL 语句中使用的字符串中的特殊字符,使得字符串是一个合法的SQL语句。
connection:
要连接的MySQL数据库
escapestring:
要转义的字符串,编码的字符是 NUL(ASCII 0),\n,\r,\,’," 和 Control-Z
最终未对用户输入的数据进行xss检测编码,直接写入数据库,所以存在存储型xss。
我们在留言板中输入name和message会存储在服务器中,并在页面回显出来
查看发现插入页面
XSS-Medium
1.代码
<?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();
}
?>
addslashes(string) :
函数返回在预定义字符之前添加反斜杠的字符串,预定义字符 ’ 、" 、\ 、NULL
strip_tags(string) :
函数剥去string字符串中的 HTML、XML 以及 PHP 的标签
htmlspecialchars(string):
把预定义的字符 “<” (小于)、 “>” (大于)、& 、‘’、“” 转换为 HTML 实体,防止浏览器将其作为HTML元素
str_replace() 函数:
以其他字符替换字符串中的一些字符(区分大小写)。
下面的输入框会被转义,上面的输入框会替换
再次输入
发现strip_tags函数把 标签给剥除了,addslashes函数把 ’ 转义成了 ’
Name只是过滤掉了script标签。我们更改限制长度,使用其他标签或者进行大小写转换或者双写绕过.
name参数对长度有限制,最大长度是10
所以先改变长度,可直接修改
输入后
XSS-High
1.代码
<?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();
}
?>
preg_replace 函数执行一个正则表达式的搜索和替换。
XSS-Impossible
1.代码
<?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();
?>
在high级别的基础上对name参数也进行了更严格的过滤,导致name参数也无法进行XSS攻击。而且使用了Anti-CSRF token防止CSRF攻击,完全杜绝了XSS漏洞和CSRF漏洞。
OGISREAL!!!