赞
踩
有关于ssdp安全的文章
ssdp攻击和防御
组播方式解决了单播情况下数据的重复拷贝及带宽的重复占用,也解决了广播方式下带宽资源的浪费,我们知道单播在发送者和每一接收者之间实现点对点网络连接。如果一台发送者同时给多个的接收者传输相同的数据,也必须相应的复制多份的相同数据包。如果有大量主机希望获得数据包的同一份拷贝时,将导致发送者负担沉重、延迟长、网络拥塞;为保证一定的服务质量需增加硬件和带宽。
组播在发送者和每一接收者之间实现点对多点网络连接。如果一台发送者同时给多个接收者传输相同的数据,也只需复制一份相同的数据包。它提高了数据传送效率,减少了骨干网络出现拥塞的可能性。实际上,组播在局域网里,是由交换机和路由器等硬件等完成一次数据的存储,而转发给其他的加入组播组的成员的。
224.0.0.0~224.0.0.255为预留的组播地址(永久组地址),地址224.0.0.0保留不做分配,其它地址供路由协议使用。实际上,这是属于D类地址。
224.0.1.0~238.255.255.255 为用户可用的组播地址(临时组地址),全网范围内有效。
plug and play 即插即用协议里面使用的 ssdp(imple Service Discovery Protocol)就是属于组播协议,简单服务发现协议,使用组播地址 239.255.255.255,端口1900 。使用wireshark等该端口的包,是可以看见很多包的,因为网关也使用这一协议。实际上,里面大量充斥的是类http协议,也有ssdp ddos 攻击的可能。
Mbone是一种跨越网络。它是一个相互连接的子网和路由器的集合,这些子网和路由器支持IP组播业务流的传送。作为因特网上的虚拟网络,Mbone通过隧道(Tunneling)来旁路因特网上无组播能力的路由器。但是,不是所有路由器能够支持这种网络,所以,这个只能是实验性质,所以,组播,一般只能在局域网里实现。
以下用用实例来说明, c# 和 c++来实现ssdp协议的组播,看似简短,但是以下程序真的是一个小却能使用的ssdp搜索程序,加上tcp的接收和发送,就可以做控制点,凡是有开始,从这个简单的c#程序着手,会有收获。
using System; using System.Text; using System.Net; using System.Net.Sockets; namespace ssdp { class Program { static void Main(string[] args) { IPEndPoint LocalEndPoint = new IPEndPoint(IPAddress.Any, 23000); IPEndPoint MulticastEndPoint = new IPEndPoint(IPAddress.Parse("239.255.255.250"), 1900); Socket UdpSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); UdpSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true); UdpSocket.Bind(LocalEndPoint); UdpSocket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.AddMembership, new MulticastOption(MulticastEndPoint.Address, IPAddress.Any)); UdpSocket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.MulticastTimeToLive, 2); UdpSocket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.MulticastLoopback, true); Console.WriteLine("UDP-Socket setup done...\r\n"); string SearchString = "M-SEARCH * HTTP/1.1\r\nHOST:239.255.255.250:1900\r\nMAN:\"ssdp:discover\"\r\nST:ssdp:all\r\nMX:3\r\n\r\n"; UdpSocket.SendTo(Encoding.UTF8.GetBytes(SearchString), SocketFlags.None, MulticastEndPoint); Console.WriteLine("M-Search sent...\r\n"); byte[] ReceiveBuffer = new byte[3200]; int ReceivedBytes = 0; while (true) { if (UdpSocket.Available > 0) { ReceivedBytes = UdpSocket.Receive(ReceiveBuffer, SocketFlags.None); if (ReceivedBytes > 0) { Console.WriteLine(Encoding.UTF8.GetString(ReceiveBuffer,0, ReceivedBytes)); } } } } } }
/* * author :qianbo * function:组播类 * 注意生成对象发送和接收是两个,生成根据 SOKM_REV 还是SOKM_SND */ #ifndef __GROUPSOCK_H1_ #define __GROUPSOCK_H1_ #ifdef WIN32 #include <winsock2.h> #include <ws2tcpip.h> #endif #include <stdio.h> namespace CorePhone { enum{ SOCKM_REV, SOCKM_SND }; #define BUFSIZE 1500 class CGroupSock { private: //以下为第二版多播通信, WSADATA _wsd; struct sockaddr_in _local, _remote, _from; SOCKET _sock, _sockM; int _len ;//= sizeof(struct sockaddr_in), int _optval; int _ret; int _Receive_Send; //(0,1) private: BOOL _isConnected; protected: //BOOL InitWinsock2(); public: BOOL Initialize(int RS); BOOL JoinGroup(const char* ip = NULL,int port = 0); BOOL SendTo(const char *pBuf,int nlen); int ReceiveData(char *pBuf,int bufferlen); public: CGroupSock(void); ~CGroupSock(void); }; }; #endif /* Author:钱波 email: 418511899@qq.com wei: 18091589062 func :类 windows 下组播 time: 2018年5月30日 */ #include "GroupSock.h" namespace CorePhone { CGroupSock::CGroupSock(void) { _len = sizeof(struct sockaddr_in); } CGroupSock::~CGroupSock(void) { closesocket(_sock); } BOOL CGroupSock::Initialize(int RS) { _Receive_Send = RS; return 0; } BOOL CGroupSock::JoinGroup(const char* ip, int port) { // //以下为第二版windows多播通信,加入了根通信 if ((_sock = WSASocket(AF_INET, SOCK_DGRAM, 0, NULL, 0, WSA_FLAG_MULTIPOINT_C_LEAF | WSA_FLAG_MULTIPOINT_D_LEAF | WSA_FLAG_OVERLAPPED)) == INVALID_SOCKET) { printf("socket failed with: %d\n", WSAGetLastError()); return FALSE; } // Bind to the local interface. This is done to receive data. _local.sin_family = AF_INET; //_local.sin_port = 0;//htons(port); _local.sin_port = 0; if (_Receive_Send == SOCKM_REV) _local.sin_port = htons(port); _local.sin_addr.s_addr = INADDR_ANY; char optval = FALSE; // 屏蔽回播 if (setsockopt(_sock, SOL_SOCKET, SO_REUSEADDR, (const char *)&optval, sizeof(int)) < 0) { return FALSE; } if (bind(_sock, (struct sockaddr *)&_local, sizeof(_local)) == SOCKET_ERROR) { printf("bind failed with: %d\n", WSAGetLastError()); closesocket(_sock); WSACleanup(); return FALSE; } // Setup the SOCKADDR_IN structure describing the multicast // group we want to join // _remote.sin_family = AF_INET; _remote.sin_port = htons(port); _remote.sin_addr.s_addr = inet_addr(ip); // // Change the TTL to something more appropriate // _optval = 32; if (setsockopt(_sock, IPPROTO_IP, IP_MULTICAST_TTL, (char *)&_optval, sizeof(int)) == SOCKET_ERROR) { printf("setsockopt(IP_MULTICAST_TTL) failed: %d\n", WSAGetLastError()); closesocket(_sock); WSACleanup(); return FALSE; } // Disable loopback if needed // _optval = 0; if (setsockopt(_sock, IPPROTO_IP, IP_MULTICAST_LOOP, (char *)&_optval, sizeof(_optval)) == SOCKET_ERROR) { printf("setsockopt(IP_MULTICAST_LOOP) failed: %d\n", WSAGetLastError()); closesocket(_sock); WSACleanup(); return FALSE; } if ((_sockM = WSAJoinLeaf(_sock, (SOCKADDR *)&_remote, sizeof(_remote), NULL, NULL, NULL, NULL, JL_BOTH)) == INVALID_SOCKET) { printf("WSAJoinLeaf() failed: %d\n", WSAGetLastError()); closesocket(_sock); WSACleanup(); _isConnected = FALSE; return FALSE; } _isConnected = TRUE; return TRUE; } BOOL CGroupSock::SendTo(const char *pBuf, int len) { if (sendto(_sock, pBuf, len, 0, (struct sockaddr *)&_remote, sizeof(_remote)) == SOCKET_ERROR) { printf("sendto failed with: %d\n", WSAGetLastError()); closesocket(_sockM); closesocket(_sock); WSACleanup(); return FALSE; } return TRUE; } int CGroupSock::ReceiveData(char *pBuf, int BufLen) { int ret = 0; if ((ret = recvfrom(_sock, pBuf, BufLen, 0, (struct sockaddr *)&_from, &_len)) == SOCKET_ERROR) { //printf("recvfrom failed with: %d\n", WSAGetLastError()); closesocket(_sockM); closesocket(_sock); WSACleanup(); return -1; } return ret; } }
从上可以看出网关和chrome都在发ssdp信息,而chrome是发的搜索信息,网关噼里啪啦发了一堆回应信息
#include <iostream> #include <string> #include <boost/asio.hpp> #include "boost/bind.hpp" //ssdp 协议 const short multicast_port = 1900; class receiver { public: receiver(boost::asio::io_context& io_service, const boost::asio::ip::address& listen_address, const boost::asio::ip::address& multicast_address) : socket_(io_service) { // Create the socket so that multiple may be bound to the same address. boost::asio::ip::udp::endpoint listen_endpoint( listen_address, multicast_port); socket_.open(listen_endpoint.protocol()); socket_.set_option(boost::asio::ip::udp::socket::reuse_address(true)); socket_.bind(listen_endpoint); // Join the multicast group. socket_.set_option( boost::asio::ip::multicast::join_group(multicast_address)); socket_.async_receive_from( boost::asio::buffer(data_, max_length), sender_endpoint_, boost::bind(&receiver::handle_receive_from, this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred)); } void handle_receive_from(const boost::system::error_code& error, size_t bytes_recvd) { if (!error) { std::cout.write(data_, bytes_recvd); std::cout << std::endl; socket_.async_receive_from( boost::asio::buffer(data_, max_length), sender_endpoint_, boost::bind(&receiver::handle_receive_from, this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred)); } } private: boost::asio::ip::udp::socket socket_; boost::asio::ip::udp::endpoint sender_endpoint_; enum { max_length = 1024 }; char data_[max_length]; }; int main(int argc, char* argv[]) { try { boost::asio::io_context io_service; receiver r(io_service, boost::asio::ip::address::from_string("192.168.1.144"), boost::asio::ip::address::from_string("239.255.255.250")); io_service.run(); } catch (std::exception& e) { std::cerr << "Exception: " << e.what() << "\n"; } return 0; }
这一次是接收信息,未完待续,下面一节会讲SSDP及DDOS攻击,以及ssdp设备发现的过程。以及如何攻击这种协议。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。