From acca57079f539a39ee823c15357ba47daa50fdb1 Mon Sep 17 00:00:00 2001 From: Jacob van Walraven Date: Tue, 25 May 2021 08:50:42 +1200 Subject: [PATCH 1/2] Add RPC module, add kerberos module, improve LLDP module --- lib/libprotoident.h | 2 ++ lib/proto_common.cc | 8 ++++++ lib/proto_common.h | 1 + lib/proto_manager.cc | 2 ++ lib/tcp/Makefile.am | 2 ++ lib/tcp/lpi_kerberos.cc | 52 +++++++++++++++++++++++++++++++++++ lib/tcp/lpi_ldap.cc | 16 +++++++---- lib/tcp/lpi_rpc.cc | 61 +++++++++++++++++++++++++++++++++++++++++ lib/tcp/tcp_protocols.h | 2 ++ 9 files changed, 141 insertions(+), 5 deletions(-) create mode 100644 lib/tcp/lpi_kerberos.cc create mode 100644 lib/tcp/lpi_rpc.cc diff --git a/lib/libprotoident.h b/lib/libprotoident.h index 6ea9cec7..7455744c 100644 --- a/lib/libprotoident.h +++ b/lib/libprotoident.h @@ -403,6 +403,8 @@ typedef enum { LPI_PROTO_TRANSOCKS, LPI_PROTO_RAGNAROK_ONLINE, LPI_PROTO_ETHERNETIP, + LPI_PROTO_KERBEROS, + LPI_PROTO_RPC, /* UDP Protocols */ LPI_PROTO_UDP, diff --git a/lib/proto_common.cc b/lib/proto_common.cc index 6fffd05b..c5888dda 100644 --- a/lib/proto_common.cc +++ b/lib/proto_common.cc @@ -74,6 +74,14 @@ bool match_chars_either(lpi_data_t *data, char a, char b, char c, return false; } +bool match_chars_both(lpi_data_t *data, char a, char b, char c, char d) { + if (!MATCH(data->payload[0], a, b, c, d)) + return false; + if (!MATCH(data->payload[1], a, b, c, d)) + return false; + return true; +} + bool match_payload_length(uint32_t payload, uint32_t payload_len) { uint32_t header = 0; diff --git a/lib/proto_common.h b/lib/proto_common.h index 679f784b..b01a1965 100644 --- a/lib/proto_common.h +++ b/lib/proto_common.h @@ -125,6 +125,7 @@ bool match_str_both(lpi_data_t *data, const char *string1, const char *string2); bool match_chars_either(lpi_data_t *data, char a, char b, char c, char d); +bool match_chars_both(lpi_data_t *data, char a, char b, char c, char d); bool match_payload_length(uint32_t payload, uint32_t payload_len); bool match_ip_address_both(lpi_data_t *data); bool match_file_header(uint32_t payload); diff --git a/lib/proto_manager.cc b/lib/proto_manager.cc index 4d9f12a3..1a4a4913 100644 --- a/lib/proto_manager.cc +++ b/lib/proto_manager.cc @@ -178,6 +178,7 @@ int register_tcp_protocols(LPIModuleMap *mod_map) { register_kankan_tcp(mod_map); register_kaseya(mod_map); register_kaspersky(mod_map); + register_kerberos(mod_map); register_kik(mod_map); register_kingofglory_tcp(mod_map); register_kuaibo(mod_map); @@ -253,6 +254,7 @@ int register_tcp_protocols(LPIModuleMap *mod_map) { register_remote_manipulator(mod_map); register_revolver_nblbt(mod_map); register_rfb(mod_map); + register_rpc(mod_map); register_rpcscan(mod_map); register_rrtv(mod_map); register_rsync(mod_map); diff --git a/lib/tcp/Makefile.am b/lib/tcp/Makefile.am index 4531a579..1f891a8f 100644 --- a/lib/tcp/Makefile.am +++ b/lib/tcp/Makefile.am @@ -111,6 +111,7 @@ libprotoident_tcp_la_SOURCES = \ lpi_kankan_tcp.cc \ lpi_kaseya.cc \ lpi_kaspersky.cc \ + lpi_kerberos.cc \ lpi_kik.cc \ lpi_kingofglory_tcp.cc \ lpi_kuaibo.cc \ @@ -186,6 +187,7 @@ libprotoident_tcp_la_SOURCES = \ lpi_remote_manipulator.cc \ lpi_revolver_nblbt.cc \ lpi_rfb.cc \ + lpi_rpc.cc \ lpi_rpcscan.cc \ lpi_rrtv.cc \ lpi_rsync.cc \ diff --git a/lib/tcp/lpi_kerberos.cc b/lib/tcp/lpi_kerberos.cc new file mode 100644 index 00000000..9afbd44d --- /dev/null +++ b/lib/tcp/lpi_kerberos.cc @@ -0,0 +1,52 @@ +/* + * + * Copyright (c) 2011-2016 The University of Waikato, Hamilton, New Zealand. + * All rights reserved. + * + * This file is part of libprotoident. + * + * This code has been developed by the University of Waikato WAND + * research group. For further information please see http://www.wand.net.nz/ + * + * libprotoident is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * libprotoident is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + * + * + */ + +#include "libprotoident.h" +#include "proto_manager.h" +#include "proto_common.h" + +static inline bool match_kerberos(lpi_data_t *data, lpi_module_t *mod UNUSED) { + + /* Quite a weak rule, first 4 bytes of kerberos is the record length :/ */ + + if (data->server_port == 88) + return true; + + return false; +} + +static lpi_module_t lpi_kerberos = { + LPI_PROTO_KERBEROS, + LPI_CATEGORY_KEY_EXCHANGE, + "Kerberos", + 200, + match_kerberos +}; + +void register_kerberos(LPIModuleMap *mod_map) { + register_protocol(&lpi_kerberos, mod_map); +} + diff --git a/lib/tcp/lpi_ldap.cc b/lib/tcp/lpi_ldap.cc index 80f86149..c45f4d01 100644 --- a/lib/tcp/lpi_ldap.cc +++ b/lib/tcp/lpi_ldap.cc @@ -30,7 +30,7 @@ #include "proto_manager.h" #include "proto_common.h" -static inline bool match_ldap_payload(uint32_t payload, uint32_t len) { +static inline bool match_ldap_payload(uint32_t payload, uint32_t len, uint16_t server_port) { uint8_t *byte = ((uint8_t *)&payload); uint16_t struct_len = 0; @@ -40,9 +40,10 @@ static inline bool match_ldap_payload(uint32_t payload, uint32_t len) { byte ++; + // multibyte lengths? if (((*byte) & 0x80) == 0x80) { uint8_t bytes_required = ((*byte) & 0x7f); - if (bytes_required > 2 || bytes_required == 0) + if (bytes_required == 0) return false; if (bytes_required == 1) { @@ -52,10 +53,15 @@ static inline bool match_ldap_payload(uint32_t payload, uint32_t len) { struct_len = 3 + ((uint8_t)(*byte)); if (!MATCH(payload, 0x30, ANY, ANY, 0x02)) return false; - } else { + } else if (bytes_required == 2) { struct_len = 4 + ntohs(*((uint16_t *)(byte + 1))); if (!MATCH(payload, 0x30, ANY, ANY, ANY)) return false; + } else { + // the length is now past the first 4 bytes of payload so we are unable + // to check it, fallback to port in this case + if (server_port == 389) + return true; } } else { if (!MATCH(payload, 0x30, ANY, 0x02, 0x01)) @@ -75,9 +81,9 @@ static inline bool match_ldap_payload(uint32_t payload, uint32_t len) { static inline bool match_ldap(lpi_data_t *data, lpi_module_t *mod UNUSED) { - if (!match_ldap_payload(data->payload[0], data->payload_len[0])) + if (!match_ldap_payload(data->payload[0], data->payload_len[0], data->server_port)) return false; - if (!match_ldap_payload(data->payload[1], data->payload_len[1])) + if (!match_ldap_payload(data->payload[1], data->payload_len[1], data->server_port)) return false; return true; diff --git a/lib/tcp/lpi_rpc.cc b/lib/tcp/lpi_rpc.cc new file mode 100644 index 00000000..54ae0b9c --- /dev/null +++ b/lib/tcp/lpi_rpc.cc @@ -0,0 +1,61 @@ +/* + * + * Copyright (c) 2011-2016 The University of Waikato, Hamilton, New Zealand. + * All rights reserved. + * + * This file is part of libprotoident. + * + * This code has been developed by the University of Waikato WAND + * research group. For further information please see http://www.wand.net.nz/ + * + * libprotoident is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * libprotoident is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + * + * + */ + +#include + +#include "libprotoident.h" +#include "proto_manager.h" +#include "proto_common.h" + +#define PDU_TYPE(x) (data->payload[0] & 0xff0000) >> 16 + +static inline bool match_rpc(lpi_data_t *data, lpi_module_t *mod UNUSED) { + + if (data->server_port != 135 && data->client_port != 135) + return false; + + // valid PDUs are 0 - 19 + if (PDU_TYPE(data->payload[0]) > 19 || PDU_TYPE(data->payload[1]) > 19) + return false; + + if (match_chars_both(data, 0x05, 0x00, ANY, 0x03)) + return true; + + return false; +} + +static lpi_module_t lpi_rpc = { + LPI_PROTO_RPC, + LPI_CATEGORY_SERVICES, + "RPC", + 200, + match_rpc +}; + +void register_rpc(LPIModuleMap *mod_map) { + register_protocol(&lpi_rpc, mod_map); +} + diff --git a/lib/tcp/tcp_protocols.h b/lib/tcp/tcp_protocols.h index 89c2bf7e..e3086f83 100644 --- a/lib/tcp/tcp_protocols.h +++ b/lib/tcp/tcp_protocols.h @@ -139,6 +139,7 @@ void register_kakao(LPIModuleMap *mod_map); void register_kankan_tcp(LPIModuleMap *mod_map); void register_kaseya(LPIModuleMap *mod_map); void register_kaspersky(LPIModuleMap *mod_map); +void register_kerberos(LPIModuleMap *mod_map); void register_kik(LPIModuleMap *mod_map); void register_kingofglory_tcp(LPIModuleMap *mod_map); void register_kuaibo(LPIModuleMap *mod_map); @@ -214,6 +215,7 @@ void register_relay(LPIModuleMap *mod_map); void register_remote_manipulator(LPIModuleMap *mod_map); void register_revolver_nblbt(LPIModuleMap *mod_map); void register_rfb(LPIModuleMap *mod_map); +void register_rpc(LPIModuleMap *mod_map); void register_rpcscan(LPIModuleMap *mod_map); void register_rrtv(LPIModuleMap *mod_map); void register_rsync(LPIModuleMap *mod_map); From 1ca21135f892d51f5680932b5a09d8067d7f37fc Mon Sep 17 00:00:00 2001 From: Jacob van Walraven Date: Tue, 25 May 2021 09:05:39 +1200 Subject: [PATCH 2/2] Improve comment --- lib/tcp/lpi_kerberos.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/tcp/lpi_kerberos.cc b/lib/tcp/lpi_kerberos.cc index 9afbd44d..c1f052d0 100644 --- a/lib/tcp/lpi_kerberos.cc +++ b/lib/tcp/lpi_kerberos.cc @@ -30,7 +30,8 @@ static inline bool match_kerberos(lpi_data_t *data, lpi_module_t *mod UNUSED) { - /* Quite a weak rule, first 4 bytes of kerberos is the record length :/ */ + /* Quite a weak rule, first 4 bytes of kerberos is the record length which + * is spread over multiple packets */ if (data->server_port == 88) return true;