目录
1、XSS也是属于注入攻击的一类,他是通过构造一个JS代码,注入到网页中,由用户的浏览器来请求源码且运行达到攻击的效果;
9、XSS很多时候就是一边测试性的输入一边查看html源码,可以通过查看源码查看系统对我构造的js注入做了什么防御;
2、DOM型XSS --向源html码中插入代码,破坏源DOM
XSS总结知识点
1、XSS也是属于注入攻击的一类,他是通过构造一个JS代码,注入到网页中,由用户的浏览器来请求源码且运行达到攻击的效果;
2、XSS的危害
3、XSS产生的原因
没有对用户输入数据进行转义过滤,导致有了完整的标签js代码出现了;
4、反射性XSS
5、存储型XSS
6、DOM的XSS
DOM的XSS是客户端通过本地的DOM,动态的将数据和html结合输出样式到页面;
我们的DOM XSS就是想办法修改客户端的网页DOM结构,想办法插入恶意代码,从而获取用户的一些信息
7、XSS的事件触发
第二个是:当鼠标对焦到失效图片上时,就会触发该事件;
这个事件不只可以在图片上使用,事件还可以在其他很多地方使用
js的触发事件还有很多很多,自己慢慢积累;
8、XSS的防御及修复
9、XSS很多时候就是一边测试性的输入一边查看html源码,可以通过查看源码查看系统对我构造的js注入做了什么防御;
因为很多时候你是看不到防御js注入的源码的,所以就只能通过一边尝试js注入,一边通过html源码来查看系统对我的js注入实行了什么防御操作
10、XSS的绕过
我们XSS的过滤无法就是通过正则表达式进行一些个过滤,那么我们的这个就XSS的绕过其实就和MySQL的绕过差不了多少;
我们就可以使用
1、大小写绕过
2、双重编码绕过:但是编码绕过的话一般是会被解码的:举个例子,我们使用的url编码绕过,但是url编码到达后端是会被解码的,那么我们就应当使用双重编码/多重编码,这样到达后端即使解码了,数据还是处于编码的形式,那么就不会被过滤了;然后这个编码的数据又返回给浏览器的时候又会被再次解码,那么我们的数据就会被还原了;而且我们浏览器是可以执行明文的html和js的;因此即使js代码在回浏览器上才解码了,也不算晚;
3、双写绕过
4、Unicode编码绕过:正常我们浏览器向服务器发送数据只会url的编解码,不会Unicode的编解码;只有服务器返回回来数据到浏览器上后,才会对数据才行进行url边界码,然后再进行Unicode的编解码;
因此当你使用Unicode编码之后,浏览器向服务器发送过去
5、当你的单双引号无法闭合的时候,那个这个注入点肯定就是没用的,那么我们就尝试去找到其他的注入点;
例题篇:
1、XSS反射型:就是我们在向服务器请求数据的时候,会有一个输入的过程,我在输入过程中故意输入了一个js脚本;然后服务器就会接收我们这个js脚本并同他的html代码结合然后一起返回给我,这样我的js代码就算是注入到我们的html源码中了;
因此如果我们需要对用户构成威胁,则我们需要首先构造一个链接等东西,里面蕴含了我的js脚本,然后用户点击这个链接进行输入,然后发送给服务器的时候,用户就会连同我的js脚本一起发送,然后服务器就会接收到我的js脚本然后将这个js脚本镶嵌在html源码中了;
服务器再将镶嵌了js源码的html运行,然后将结果返回给客户端浏览器,这样用户就会被造成损失;
注意:js的运行是在服务器上进行的,运行结束的html源码然后才返回给客户端
XSS反射性说白了就是服务器对用户的输入过滤不严格造成的!!
---前端可以直接执行js代码,因此当我们的js代码镶嵌在前端中时,可以直接被执行;
2、DOM型XSS --向源html码中插入代码,破坏源DOM
--1、
--1、<h2 id="spaghet"></h2><script>
spaghet.innerHTML = " Toucha Ma Spaghet!"
</script>
这里调用了我们js中每个标签都有的一个方法:inner HTML方法,这个方法可以将对应值插入id对应的标签底下。也可以将标签插入到id对应的标签底下
例题1:
<h2 id="spaghet"></h2><script>
spaghet.innerHTML = (new URL(location).searchParams.get('somebody') || "Somebody") + " Toucha Ma Spaghet!"</script>
1、解决办法:?somebody=<script>alert(1)</script>
看似这种是可以的,但是因为官方认为innerHTML方法太不安全了,所以就对该方法做了限制,只要是想通过innerhtml方法实现添加<script>标签,那么该标签就会被变成一个没有任何功能的<script/>标签;
2、因此我们还可以使用:
?somebody=<img%20src=1%20οnerrοr=alert(1337)>
//意思:当我们的图片加载不出来就会执行js的onerror代码:alert(1337)
--2、例题2
<!-- Challenge --><h2 id="maname"></h2><script>
let jeff = (new URL(location).searchParams.get('jeff') || "JEFFF")
let ma = ""
eval(`ma = "Ma name ${jeff}"`)
setTimeout(_ => {
maname.innerText = ma
}, 1000)</script>
我们的js中也有执行函数eval
注意我们的js中eval也是将字符串当作代码执行,但是这里之所以还要逃出双引号,是因为本身获取的值就是一个字符串,字符串外面再套一层字符串就会执行不了
反引号也不能将字符串当作命令执行(严格来说Linux也不允许这样,但是Linux的部分命令可以这样);
解决方法:?jeff=";alert(1);" //为了不让alert变成字符串,无法执行,则必须逃出单引号
--3、例题3,不能于用户交互
1、这里看到我们写入是只能在input元素中,
因此我们可以这样:?wey=aa" οnclick="alert(1) / aa" oncfocus="alert(1)
这样肯定没问题,但是我们这里是不能于用户交互的,因为我们的input元素,因此这个onclick是必须点击才能触发的
2、但是我们可以使用另一个方法wey=aa" οnfοcus=alert(1) autofocus="
就是正常对焦才能触发的函数,我们再来一个自动对焦;那么函数就能自动调用了
我们的οnclick=这种触发事件调用的值必须要加上双引号;但是很多时候其实浏览器会自动帮助我们加上;所以这题其实我们只要逃出来双引号,后面的双引号闭合即可,即使οnclick=后买的值没有加双引号浏览器也会帮助我们加上的
--4、例题4 不能于用户交互
这里是将用户的输入当作form表达的路径,然后下面有一个2秒钟自动提交
1、办法:?ricardo=javascript:alert(1) //这样我们在自动提交到action中时,会自动触发action,自然而然的就会触发js代码
2、补充:我们的JavaScript的作用是当你的js代码是字符串时,那么你想要让系统认出你的js代码,那么就得在前面加上一个“Javascript: ” 申明头;因此,如果我们想要在href,location这种值为字符串的里面添加js代码,就必须在其里面添加" Javascript: " 申明头;
注意,我们的js代码是想要触发的,因此,我们的location="javascript:alert(1)"也是不能单独使用的;需要和触发项配合使用;比如下面第5题;
还比如我们的href=“值有js代码的时候必须写”javascript,因为里面是字符串形式的js代码
目前来,需要用到" javascript: "申明头的主要有:href,location
3、反过来也是一样,我们的form表单也是不能点击的,他不像input那样有方框可以让你点击呀,因此我们的form表单也是不能添加onclick这种事件的
--5、例题5
显然是对符号进行过滤了,且过滤了多次;
然后将这个值添加到了<h2>标签下面
--方法:?a=<img src=1 οnerrοr=location="javascript:alert%25281%2529">
看思路:1、首先,我们看到我们的这个括号这些被过滤了,因此我们的括号是需要进行编码的,然后我们就将括号进行编码成了%28%29,但是注意我们的%28%29是作为的客户端输入的,因此这个传给服务器时,还是会进行解码,依然会变成(),那我们再使用%25嘛,
%25经过url编码会变成%,因此%2528%2529经过一次url解码之后,会变成:%28%29,又因为我们的js代码是不能将符号进行编码的,因此不能这样写:οnerrοr="alert%2528%2529";
那么我们怎样才能让js中的括号允许编码,——让js代码变成字符串;也就是加入location使用,οnerrοr="location="alert%2528%2529"";
这样,我的js符号就没有编码了,因为我的js代码是location="javascript:alert%2528%2529",而alert%2528%2529是属于location的字符串的,不属于js代码;因此,在发送向浏览器的时候,我们的alert%2528%2529就变成了alert%28%29,然后以为这个alert%28%29是在location里面的,所以他不会被认为是js代码;这样将这个返回给浏览器的时候,又被解码了,又变成了(),这样浏览器就可以正常执行js代码了;
注意:1、服务器执行不了的js代码,浏览器也会继续执行!!
2、oneerror="alert(1)"这里面的alert(1),js会认为他是js代码,因为这种就是正常的js代码的写法;但是如果是把这个加入到location里面的话,系统就会认为他是字符串;
但是回到浏览器的时候,系统把他解析成()之后,浏览器一看这个字符串里面还有javascript这个申明头,那么就知道这个字符串是js代码了
因此经过正则表达式过滤之后,%28%29依然存在,就这样有发送给了客户端浏览器;
客户端浏览器再一解析,就变成了(),这样就成功运行了;
---注意:我们的location后面可以加Javascript: 声明头
--6、例题6
这里说明了不能用数字字母,显然就是想让我们用符号
这里将alert(1)进行jsfuck编码,然后再将这个编码进行url编码,最后才是将url编码后的值传递给balls ?balls=jsfuck和url编码后的值...
我们的js中可以识别jsfuck编码,因此我们的js支持对符号进行jsfuck编码和html实体编码;
问题:为啥需要进行url编码,不是浏览器会自动进行编解码吗?
因为浏览器上可能会对 + 这种类似的编码出错,然后到达服务器上就变不回 + 了
--7、例题7
这里除开的对符号过滤以外,还对alert和confirm也过滤了,这里confirm写漏了;
那我们就不能像例题6那样了,那我们该怎么办?
可以看出,他的alert只过滤了小写,没有过滤大写,那我们可以使用大写呀!
--问题又来了,我们的js是严格区分大小写的,我们转ALERT就会不起作用了呀,js就不能执行了呀!
那我们不妨将其再用函数将其转成小写怎么样?
方法1:说干就干:?mafia=Function(/Alert(1)/.source.toLowerCase())() //这个是构造函数
//source.toLowerCase()函数是将其转换成小写,最后面的()是自动执行构造函数;
我们的普通函数是不能自己执行自己的,但是我们的构造函数是可以自动执行自己的,就是在函数体最后面添加一个();
注意使用.source则必须在前面加上两个 /.../
//准确的来说其实这个是不是普通的函数,普通函数哪有可以自动执行的,其实这个是构造函数
方法2:parseint编码
?mafia=eval(8680439..toString(30))(1)
8、例题8
这篇文章没有什么好说的,他主要考察的是这个框架的过滤:黑名单
这个框架对于οnerrοr=alert(1)这种标准js进行了过滤,对于字符串中函数有Javascript:alert(1)
这种也进行了过滤;
但是没有过滤字符串tel:这种类型的js,因此我们可以尝试使用:<a id=ok href=tel:alert(1)>
我们的tel为什么也可以让浏览器执行这个js代码?
因为我们js中也有tel,cid等这些关键字/函数,那么当你在前端用这些关键字/函数的时候,浏览器就会把他看作是他能认出的语言里面的关键字,刚好js中有这个关键字,那么浏览器自然就会把他解析成我们的js代码
下面的setTimeout(ok,2000):在2秒后调用我们的ok对应的标签,也就是进入a标签,注意,这里使用setTimeout调用的话,不能使用name=ok,只能使用id=ok。
完结篇啦,哈哈哈。
本篇注意事项:
--1、题目中这种是不行的,因为onfocus是不能是字符串的;这里的onfocus进行解码之后明显是变成了字符串;
可能有人会说,这里即使不是编码,直接就是写一个wey="οnfοcus=alert(1)"为什么就可以?
因为我们的js中变量附加在标签中时,会自动把其变成普通值,而非字符串;就是说会把字符串的双引号去掉,变成一个值了;
但是如果这里进行编码了,那么我们将起双引号去掉之后,然后加入到html标签中,然后再进行实体解码,那么这个又会变成一个"οnfοcus=alert(1)"这样一个字符串了;
--2、我们的JavaScript是可以进行编码的,因为我们的Javascript本身就是应用在字符串中的,起申明作用的;所以当我们的Javascript编码且加上双引号之后,在js中就会去掉字符串属性,也就是去掉双引号;
然后添加到html中时,就会被html实体解码;然后又会变成字符串;这样也是刚刚符合JavaScript必须存在于字符串的要求;