forked from osmocom/wireshark
ipsec: Improve ESP NULL autodetection
Improve the ESP NULL autodetection, and get it closer to the heuristics in RFC 5879: Detect multiple ICV lengths - 12, 16, 24, and 32 Check padding length validity Check padding values Reject if the subdissector rejects the packet Still does not attempt to properly detect ENCR_NULL_AUTH_AES_GMAC, which has a nonzero IV. Fix #13730.
This commit is contained in:
parent
d24d27ebc1
commit
0aed38cf97
|
@ -1207,6 +1207,98 @@ export_ipsec_pdu(dissector_handle_t dissector_handle, packet_info *pinfo, tvbuff
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements much of RFC 5879, "Heuristics for Detecting ESP-NULL Packets"
|
||||
*
|
||||
* Does NOT attempt to properly detect ENCR_NULL_AUTH_AES_GMAC.
|
||||
*/
|
||||
static int
|
||||
esp_null_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *esp_tree)
|
||||
{
|
||||
int esp_packet_len, esp_pad_len, esp_icv_len, offset;
|
||||
guint encapsulated_protocol;
|
||||
guint32 saved_match_uint;
|
||||
|
||||
tvbuff_t *next_tvb;
|
||||
dissector_handle_t dissector_handle;
|
||||
|
||||
/* Possible ICV lengths to try. Per RFC 5879, smallest to largest.
|
||||
*/
|
||||
static const int icv_lengths[] = {
|
||||
12,
|
||||
16,
|
||||
24,
|
||||
32,
|
||||
-1
|
||||
};
|
||||
|
||||
esp_packet_len = tvb_reported_length(tvb);
|
||||
|
||||
for (int i = 0; (esp_icv_len = icv_lengths[i]) != -1; i++) {
|
||||
|
||||
/* Make sure the packet is not truncated before the fields
|
||||
* we need to read to determine the encapsulated protocol.
|
||||
*/
|
||||
if (tvb_bytes_exist(tvb, -(esp_icv_len + 2), 2))
|
||||
{
|
||||
offset = esp_packet_len - (esp_icv_len + 2);
|
||||
esp_pad_len = tvb_get_guint8(tvb, offset);
|
||||
encapsulated_protocol = tvb_get_guint8(tvb, offset + 1);
|
||||
dissector_handle = dissector_get_uint_handle(ip_dissector_table, encapsulated_protocol);
|
||||
if (dissector_handle == NULL) {
|
||||
continue;
|
||||
}
|
||||
if (ESP_HEADER_LEN + esp_pad_len > offset) {
|
||||
continue;
|
||||
}
|
||||
for (int j=0; j < esp_pad_len; j++) {
|
||||
if (tvb_get_guint8(tvb, offset - (j + 1)) != (esp_pad_len - j)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
saved_match_uint = pinfo->match_uint;
|
||||
pinfo->match_uint = encapsulated_protocol;
|
||||
next_tvb = tvb_new_subset_length(tvb, ESP_HEADER_LEN, offset - ESP_HEADER_LEN - esp_pad_len);
|
||||
/* If the matching dissector has been disabled or rejects the packet,
|
||||
* consider the heuristic failed.
|
||||
* XXX: Should we also catch exceptions and consider those failures too?
|
||||
*
|
||||
* Note that the case of ENCR_NULL_AUTH_AES_GMAC will find the correct
|
||||
* padding and encapsulated protocol using a 16 byte ICV, but needs to
|
||||
* skip over the 8 bytes of IV.
|
||||
*/
|
||||
if (call_dissector_only(dissector_handle, next_tvb, pinfo, proto_tree_get_parent_tree(esp_tree), NULL) == 0) {
|
||||
pinfo->match_uint = saved_match_uint;
|
||||
continue;
|
||||
}
|
||||
export_ipsec_pdu(dissector_handle, pinfo, next_tvb);
|
||||
pinfo->match_uint = saved_match_uint;
|
||||
|
||||
if (esp_tree) {
|
||||
if (esp_pad_len !=0) {
|
||||
proto_tree_add_item(esp_tree, hf_esp_pad,
|
||||
tvb, offset - esp_pad_len,
|
||||
esp_pad_len, ENC_NA);
|
||||
}
|
||||
|
||||
proto_tree_add_uint(esp_tree, hf_esp_pad_len, tvb,
|
||||
offset, 1,
|
||||
esp_pad_len);
|
||||
|
||||
proto_tree_add_uint_format(esp_tree, hf_esp_protocol, tvb,
|
||||
offset + 1, 1,
|
||||
encapsulated_protocol,
|
||||
"Next header: %s (0x%02x)",
|
||||
ipprotostr(encapsulated_protocol), encapsulated_protocol);
|
||||
}
|
||||
|
||||
return esp_icv_len;
|
||||
}
|
||||
}
|
||||
return esp_icv_len;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
capture_ah(const guchar *pd, int offset, int len, capture_packet_info_t *cpinfo, const union wtap_pseudo_header *pseudo_header)
|
||||
{
|
||||
|
@ -2179,51 +2271,24 @@ dissect_esp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
|
|||
{
|
||||
if(g_esp_enable_null_encryption_decode_heuristic)
|
||||
{
|
||||
/* Make sure the packet is not truncated before the fields
|
||||
* we need to read to determine the encapsulated protocol.
|
||||
* (Note: we assume an ICV of 12 byte length.)
|
||||
*/
|
||||
if(tvb_bytes_exist(tvb, esp_packet_len - 14, 2))
|
||||
{
|
||||
esp_pad_len = tvb_get_guint8(tvb, esp_packet_len - 14);
|
||||
encapsulated_protocol = tvb_get_guint8(tvb, esp_packet_len - 13);
|
||||
dissector_handle = dissector_get_uint_handle(ip_dissector_table, encapsulated_protocol);
|
||||
if (dissector_handle && (ESP_HEADER_LEN + 14 + esp_pad_len) <= esp_packet_len) {
|
||||
saved_match_uint = pinfo->match_uint;
|
||||
pinfo->match_uint = encapsulated_protocol;
|
||||
next_tvb = tvb_new_subset_length(tvb, ESP_HEADER_LEN, esp_packet_len - ESP_HEADER_LEN - 14 - esp_pad_len);
|
||||
export_ipsec_pdu(dissector_handle, pinfo, next_tvb);
|
||||
call_dissector(dissector_handle, next_tvb, pinfo, tree);
|
||||
pinfo->match_uint = saved_match_uint;
|
||||
decrypt_dissect_ok = TRUE;
|
||||
}
|
||||
}
|
||||
esp_icv_len = esp_null_heur(tvb, pinfo, esp_tree);
|
||||
}
|
||||
|
||||
if(decrypt_dissect_ok)
|
||||
if(esp_icv_len != -1)
|
||||
{
|
||||
offset = esp_packet_len - esp_icv_len;
|
||||
if(esp_tree)
|
||||
{
|
||||
proto_tree_add_uint(esp_tree, hf_esp_pad_len, tvb,
|
||||
esp_packet_len - 14, 1,
|
||||
esp_pad_len);
|
||||
|
||||
proto_tree_add_uint_format(esp_tree, hf_esp_protocol, tvb,
|
||||
esp_packet_len - 13, 1,
|
||||
encapsulated_protocol,
|
||||
"Next header: %s (0x%02x)",
|
||||
ipprotostr(encapsulated_protocol), encapsulated_protocol);
|
||||
|
||||
/* Make sure we have the auth trailer data */
|
||||
if(tvb_bytes_exist(tvb, esp_packet_len - 12, 12))
|
||||
if(tvb_bytes_exist(tvb, offset, esp_icv_len))
|
||||
{
|
||||
proto_tree_add_item(esp_tree, hf_esp_icv, tvb, esp_packet_len - 12, 12, ENC_NA);
|
||||
icv_item = proto_tree_add_item(esp_tree, hf_esp_icv, tvb, offset, esp_icv_len, ENC_NA);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Truncated so just display what we have */
|
||||
proto_tree_add_bytes_format(esp_tree, hf_esp_icv, tvb, esp_packet_len - 12,
|
||||
12 - (esp_packet_len - tvb_captured_length(tvb)),
|
||||
icv_item = proto_tree_add_bytes_format(esp_tree, hf_esp_icv, tvb, offset,
|
||||
esp_icv_len - (esp_packet_len - tvb_captured_length(tvb)),
|
||||
NULL, "Integrity Check Value (truncated)");
|
||||
}
|
||||
}
|
||||
|
@ -2482,8 +2547,9 @@ proto_register_ipsec(void)
|
|||
prefs_register_bool_preference(esp_module, "enable_null_encryption_decode_heuristic",
|
||||
"Attempt to detect/decode NULL encrypted ESP payloads",
|
||||
"This is done only if the Decoding is not SET or the packet does not belong to a SA. "
|
||||
"Assumes a 12 byte auth (HMAC-SHA1-96/HMAC-MD5-96/AES-XCBC-MAC-96) "
|
||||
"and attempts decode based on the ethertype 13 bytes from packet end",
|
||||
"Tries ICV lengths of 12, 16, 24, and 32 bytes, checks for valid padding, "
|
||||
"and attempts to decode based on the derived Next Header field. "
|
||||
"Does not detect ENCR_NULL_AUTH_AES_GMAC (i.e. assumes 0 length IV)",
|
||||
&g_esp_enable_null_encryption_decode_heuristic);
|
||||
|
||||
prefs_register_bool_preference(esp_module, "do_esp_sequence_analysis",
|
||||
|
|
Loading…
Reference in New Issue