From: Shravan Rangarajuvenkata (shrarang) Date: Wed, 6 Oct 2021 14:06:54 +0000 (+0000) Subject: Merge pull request #3084 in SNORT/snort3 from ~SATHIRKA/snort3:rpc_assert_failure... X-Git-Tag: 3.1.14.0~1 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=b84900253281fbcac99aebedcd3b4c0b8ffaea5e;p=thirdparty%2Fsnort3.git Merge pull request #3084 in SNORT/snort3 from ~SATHIRKA/snort3:rpc_assert_failure to master Squashed commit of the following: commit d4a4f383859d75e912fdd65f6d5faf2cd2ecd1b3 Author: Sreeja Athirkandathil Narayanan Date: Wed Sep 29 16:28:36 2021 -0400 appid: Enhance RPC service detector to handle RPC Bind version 3 --- diff --git a/src/network_inspectors/appid/appid_session.cc b/src/network_inspectors/appid/appid_session.cc index 756a7c650..f874e573f 100644 --- a/src/network_inspectors/appid/appid_session.cc +++ b/src/network_inspectors/appid/appid_session.cc @@ -211,11 +211,18 @@ AppIdSession* AppIdSession::create_future_session(const Packet* ctrlPkt, const S uint16_t cliPort, const SfIp* srvIp, uint16_t srvPort, IpProtocol proto, SnortProtocolId snort_protocol_id, bool swap_app_direction, bool bidirectional) { - char src_ip[INET6_ADDRSTRLEN]; - char dst_ip[INET6_ADDRSTRLEN]; enum PktType type = get_pkt_type_from_ip_proto(proto); - assert(type != PktType::NONE); + if (type == PktType::NONE) + { + if (appidDebug->is_active()) + LogMessage("AppIdDbg %s Failed to create a related flow - invalid protocol %u\n", + appidDebug->get_debug_session(), (unsigned)proto); + return nullptr; + } + + char src_ip[INET6_ADDRSTRLEN]; + char dst_ip[INET6_ADDRSTRLEN]; AppIdInspector* inspector = (AppIdInspector*)ctrlPkt->flow->flow_data->get_handler(); if ((inspector == nullptr) || strcmp(inspector->get_name(), MOD_NAME)) diff --git a/src/network_inspectors/appid/service_plugins/service_rpc.cc b/src/network_inspectors/appid/service_plugins/service_rpc.cc index a8e321730..3f5cf97b3 100644 --- a/src/network_inspectors/appid/service_plugins/service_rpc.cc +++ b/src/network_inspectors/appid/service_plugins/service_rpc.cc @@ -26,6 +26,8 @@ #include "service_rpc.h" #include +#include +#include #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(USE_TIRPC) #include @@ -41,7 +43,7 @@ #include "app_info_table.h" using namespace snort; - +using namespace std; enum RPCState { @@ -78,6 +80,8 @@ enum RPCReplyState #define RPC_PROGRAM_PORTMAP 100000 #define RPC_PORTMAP_GETPORT 3 +#define RPC_BIND_PORTMAP_GETADDR 3 + #define RPC_REPLY_ACCEPTED 0 #define RPC_REPLY_DENIED 1 @@ -89,6 +93,9 @@ enum RPCReplyState /* sizeof(ServiceRPCCall)+sizeof(_SERVICE_RPC_PORTMAP)==56 */ #define RPC_MAX_TCP_PACKET_SIZE 56 +#define PROGRAM_LENGTH 4 +#define VERSION_LENGTH 4 + #pragma pack(1) struct ServiceRPCFragment @@ -115,6 +122,18 @@ struct ServiceRPCPortmapReply uint32_t port; }; +struct NetId +{ + uint32_t length; + // protocol string follows +}; + +struct UniversalAddress +{ + uint32_t length; + // universal address follows +}; + struct ServiceRPC { uint32_t xid; @@ -148,6 +167,7 @@ struct ServiceRPCData RPCTCPState tcpstate[APP_ID_APPID_SESSION_DIRECTION_MAX]; RPCTCPState tcpfragstate[APP_ID_APPID_SESSION_DIRECTION_MAX]; uint32_t program; + uint32_t program_version; uint32_t procedure; uint32_t xid; IpProtocol proto; @@ -275,6 +295,53 @@ static const RPCProgram* FindRPCProgram(uint32_t program) return rpc; } +static IpProtocol get_protocol_from_netid(const string& proto) +{ + if (proto == "tcp") + return IpProtocol::TCP; + else if (proto == "udp") + return IpProtocol::UDP; + else if (proto == "icmp") + return IpProtocol::ICMPV4; + else if (proto == "ip") + return IpProtocol::IP; + else + return IpProtocol::PROTO_NOT_SET; +} + +/* + * Universal addresses take the form h1.h2.h3.h4.p1.p2 ; where h1, h2, h3 and h4 are respectively, + * the first through fourth octets of the IP address each converted to ASCII-decimal. p1 and p2 are + * respectively, the first and second octets of the service port, each converted to ASCII-decimal. + */ +static bool validate_and_parse_universal_address(string& data, uint32_t &address, + uint16_t &port) +{ + int i = 0; + istringstream tokenizer(data); + string tok; + while (getline(tokenizer, tok, '.')) + { + int tmp = stoi(tok); + if (tmp > 255) + return false; + if (i < 4) + { + address <<= 8u; + address += tmp; + } + else + { + port <<= 8u; + port += tmp; + } + i++; + } + if (i != 6) + return false; + return true; +} + int RpcServiceDetector::validate_packet(const uint8_t* data, uint16_t size, AppidSessionDirection dir, AppIdSession& asd, Packet* pkt, ServiceRPCData* rd, const char** pname, uint32_t* program) { @@ -329,6 +396,7 @@ int RpcServiceDetector::validate_packet(const uint8_t* data, uint16_t size, Appi if (ntohl(call->version) != 2) return APPID_NOT_COMPATIBLE; rd->program = ntohl(call->program); + rd->program_version = ntohl(call->program_version); rd->procedure = ntohl(call->procedure); tmp = ntohl(call->cred.length); if (sizeof(ServiceRPCCall)+tmp > size) @@ -344,16 +412,27 @@ int RpcServiceDetector::validate_packet(const uint8_t* data, uint16_t size, Appi switch (rd->program) { case RPC_PROGRAM_PORTMAP: - switch (rd->procedure) + if (rd->program_version == 3 and rd->procedure == RPC_BIND_PORTMAP_GETADDR) + { + if (sizeof(ServiceRPCCall) + PROGRAM_LENGTH + VERSION_LENGTH + sizeof(NetId) > size) + return APPID_NOT_COMPATIBLE; + data += (PROGRAM_LENGTH + VERSION_LENGTH); + const NetId* net_id = (const NetId*) data; + tmp = ntohl(net_id->length); + if (tmp == 0 or (sizeof(ServiceRPCCall) + PROGRAM_LENGTH + VERSION_LENGTH + + sizeof(NetId) + tmp > size)) + return APPID_NOT_COMPATIBLE; + + data += sizeof(NetId); + string netid_proto(data, data + tmp); + rd->proto = get_protocol_from_netid(netid_proto); + } + else if (rd->program_version == 2 and rd->procedure == RPC_PORTMAP_GETPORT) { - case RPC_PORTMAP_GETPORT: if (end-data < (int)sizeof(ServiceRPCPortmap)) return APPID_NOT_COMPATIBLE; pm = (const ServiceRPCPortmap*)data; rd->proto = (IpProtocol)ntohl(pm->proto); - break; - default: - break; } break; default: @@ -389,14 +468,47 @@ int RpcServiceDetector::validate_packet(const uint8_t* data, uint16_t size, Appi return APPID_INPROCESS; } *program = rd->program; - const ServiceRPCPortmapReply* pmr = nullptr; switch (rd->program) { case RPC_PROGRAM_PORTMAP: - switch (rd->procedure) + if (rd->program_version == 3 and rd->procedure == RPC_BIND_PORTMAP_GETADDR) + { + if ((sizeof(ServiceRPCReply) + sizeof(UniversalAddress)) > size) + return APPID_NOMATCH; + const UniversalAddress* u_addr = (const UniversalAddress*) data; + tmp = ntohl(u_addr->length); + if (tmp == 0 or + ((sizeof(ServiceRPCReply) + sizeof(UniversalAddress) + tmp) > size)) + return APPID_NOMATCH; + uint32_t address = 0; + uint16_t port = 0; + data += sizeof(UniversalAddress); + string uaddr(data, data + tmp); + if (validate_and_parse_universal_address(uaddr, address, port)) + { + SfIp sip; + uint32_t addr = htonl(address); + sip.set(&addr, AF_INET); + const SfIp* dip = pkt->ptrs.ip_api.get_dst(); + AppIdSession* fsession = AppIdSession::create_future_session( + pkt, dip, 0, &sip, port, rd->proto, + asd.config.snort_proto_ids[PROTO_INDEX_SUNRPC]); + + if (fsession) + { + fsession->add_flow_data_id(port, this); + fsession->service_disco_state = APPID_DISCO_STATE_STATEFUL; + fsession->set_session_flags(asd.get_session_flags( + APPID_SESSION_SPECIAL_MONITORED | + APPID_SESSION_DISCOVER_APP | + APPID_SESSION_DISCOVER_USER)); + } + } + } + else if (rd->program_version == 2 and rd->procedure == RPC_PORTMAP_GETPORT) { - case RPC_PORTMAP_GETPORT: + const ServiceRPCPortmapReply* pmr = nullptr; if (end-data < (int)sizeof(ServiceRPCPortmapReply)) return APPID_NOMATCH; pmr = (const ServiceRPCPortmapReply*)data; @@ -420,9 +532,6 @@ int RpcServiceDetector::validate_packet(const uint8_t* data, uint16_t size, Appi APPID_SESSION_DISCOVER_USER)); } } - break; - default: - break; } *pname = "portmap"; break;