袁哥的cve-2014-6332poc脚本中利用构造的读写primitive关掉了IE的SafeMode,由于开启了上帝模式的IE利用VBS脚本来可以直接创建进程、读写文件等。
那么到底SafeMode是什么呢?
下面反汇编函数,是vbscript引擎用来判断是当前是否运行在安全模式的函数:
0: kd> uf vbscript!COleScript::InSafeMode
vbscript!COleScript::InSafeMode:
667fce4d f781740100000b000000 test dword ptr [ecx+174h],0Bh
667fce57 6a00 push 0
667fce59 58 pop eax
667fce5a 0f95c0 setne al
667fce5d c3 ret
当ecx+0x174
的值为0
时,等于关闭了保护模式,开启了上帝模式。那么ecx的值从哪来的呢?
在windbg中下断点vbscript!COleScript::InSafeMode
,断下后查看调用堆栈:
0: kd> kn
# ChildEBP RetAddr
00 01eecd38 66800fd3 vbscript!COleScript::InSafeMode
01 01eecdc4 66800f43 vbscript!GetObjectFromProgID+0x80
02 01eecdf4 66800eca vbscript!VbsCreateObject2+0x79
03 01eece10 667f3854 vbscript!VbsCreateObject+0x33
通过分析vbscript!VbsCreateObject2
得知,ecx
的值实际是vbscript!CScriptRuntime::GetCurrentOleScript
函数的返回值
0: kd> u vbscript!VbsCreateObject2 L 30
vbscript!VbsCreateObject2:
66800ee6 8bff mov edi,edi
66800ee8 55 push ebp
66800ee9 8bec mov ebp,esp
66800eeb 51 push ecx
66800eec 8b4d08 mov ecx,dword ptr [ebp+8]
66800eef 33c0 xor eax,eax
66800ef1 40 inc eax
66800ef2 668901 mov word ptr [ecx],ax
66800ef5 39450c cmp dword ptr [ebp+0Ch],eax
66800ef8 0f8502060200 jne vbscript!VbsCreateObject2+0x14 (66821500)
66800efe 57 push edi
66800eff e80dbfffff call vbscript!CScriptRuntime::GetCurrentOleScript (667fce11)
66800f04 33ff xor edi,edi
66800f06 8945fc mov dword ptr [ebp-4],eax
...省略部分代码
66800f43 8b4dfc mov ecx,dword ptr [ebp-4] ; ecx = CurrentOleScript
66800f46 8bf0 mov esi,eax
66800f48 e800bfffff call vbscript!COleScript::InSafeMode (667fce4d)
那vbscript!CScriptRuntime::GetCurrentOleScript
函数又是干嘛的呢?
0: kd> uf vbscript!CScriptRuntime::GetCurrentOleScript
vbscript!CScriptRuntime::GetCurrentOleScript:
667fce11 ff3584908466 push dword ptr [vbscript!g_luTls (66849084)] ds:0023:66849084=0000004b
667fce17 ff15c8127f66 call dword ptr [vbscript!_imp__TlsGetValue (667f12c8)]
667fce1d 85c0 test eax,eax
1: kd> r eax
eax=01874180 ; GetTlsValue返回值
667fce1f 0f84a3d40100 je vbscript!CScriptRuntime::GetCurrentOleScript+0x10 (6681a2c8)
667fce25 8b400c mov eax,dword ptr [eax+0Ch]
667fce28 c3 ret
1: kd> r eax
eax=069e9ac8 ; 传给InSafeMode函数的参数,也就是我们要找的ecx的值
继续分析得知GetCurrentOleScript
返回值,实际是 【GetTlsValue() + 0xC】得到的!GetTlsValue的参数是0x4B
GetTlsValue
函数是线程局部存储函数,用来读取当前线程中保存的Tls对应槽的变量,0x4B == Tls槽
GetTlsValue
函数分析:
KERNELBASE!TlsGetValue:
75666818 8bff mov edi,edi
7566681a 55 push ebp
7566681b 8bec mov ebp,esp
7566681d 64a118000000 mov eax,dword ptr fs:[00000018h] fs:003b:00000018=7ffd9000 == TEB
75666823 8b4d08 mov ecx,dword ptr [ebp+8] ; ecx = 0x4B = TLS索引
75666826 83603400 and dword ptr [eax+34h],0 ; 清空LastErrorValue
7566682a 83f940 cmp ecx,40h ; 检查索引是否大于0x40
7566682d 0f83738c0000 jae KERNELBASE!TlsGetValue+0x20 (7566f4a6) ; 大于则跳
75666833 8b8488100e0000 mov eax,dword ptr [eax+ecx*4+0E10h] ; 小于0x40,直接读取(TEB.TlsSlots + 4 * 索引)
7566683a 5d pop ebp
7566683b c20400 ret 4
大于0x40跳转的位置:
0: kd> u 7566f4a6
KERNELBASE!TlsGetValue+0x20:
7566f4a6 81f940040000 cmp ecx,440h ;判断是否小于0x440,小于则跳
7566f4ac 7205 jb KERNELBASE!TlsGetValue+0x38 (7566f4b3)
7566f4ae e999c00100 jmp KERNELBASE!TlsGetValue+0x28 (7568b54c)
小于0x440跳转的位置:
7566f4b3 8b80940f0000 mov eax,dword ptr [eax+0F94h] ; +0xf94 TEB.TlsExpansionSlots 从扩展槽中读取
7566f4b9 85c0 test eax,eax
7566f4bb 0f84eedeffff je KERNELBASE!TlsGetValue+0x32 (7566d3af)
7566f4c1 8b848800ffffff mov eax,dword ptr [eax+ecx*4-100h] ; 读取(扩展槽基址+4*槽索引-0x100)
7566f4c8 e96d73ffff jmp KERNELBASE!TlsGetValue+0x34 (7566683a)
总结:
IE的VBScript引擎中判断当前是否处于安全模式的方式,首先通过0x4B作为TLS槽,从TLS变量中获取CurrentOleScript对象, 这个CurrentOleScript对象偏移0x174的位置,就是判断是否在安全模式。
如果非0则不再安全模式!!