Eu estava olhando para CVE-2024-53259 , onde um invasor pode injetar mensagem ICMP Fragmentation Needed em um host com conexão QUIC usando a biblioteca quic-go. A causa é a configuração IP_PMTUDISC_DO
da opção socket do quic-go ao sondar seu caminho mtu.
O que eu realmente não entendo é que, embora a página CVE diga basicamente que o kernel recebe o pacote ICMP do invasor e atualiza o caminho mtu, parece que o kernel do Linux manipula o pacote separadamente por dst ip e src ip para erro ICMP recebido, construindo 'chave de fluxo' (estou olhando para a função ipv4_sk_update_pmtu ):
void ipv4_sk_update_pmtu(struct sk_buff *skb, struct sock *sk, u32 mtu)
{
const struct iphdr *iph = (const struct iphdr *)skb->data;
struct flowi4 fl4;
struct rtable *rt;
struct dst_entry *odst = NULL;
bool new = false;
struct net *net = sock_net(sk);
bh_lock_sock(sk);
if (!ip_sk_accept_pmtu(sk))
goto out;
odst = sk_dst_get(sk);
if (sock_owned_by_user(sk) || !odst) {
__ipv4_sk_update_pmtu(skb, sk, mtu);
goto out;
}
// this function calls flowi4_init_output inside, which takes src/dst addr as arguments
__build_flow_key(net, &fl4, sk, iph, 0, 0, 0, 0, 0);
rt = dst_rtable(odst);
if (odst->obsolete && !odst->ops->check(odst, 0)) {
rt = ip_route_output_flow(sock_net(sk), &fl4, sk);
if (IS_ERR(rt))
goto out;
new = true;
}
...
}
Se os pacotes forem manipulados com base em seus endereços src/dst, o pacote do invasor não deve interromper a conexão existente porque o pacote tem um endereço IP de origem diferente. Por que esse tipo de ataque está disponível?
desde já, obrigado
Porque os RFCs do DHCP dizem que devemos aceitar atualizações de MTU de caminho de qualquer pessoa.
A alternativa seria aceitar apenas atualizações de PMTU de nós ao longo do caminho, que podem mudar com cada pacote.
Considere a sobrecarga de preencher e manter uma lista de todos os nós ao longo do caminho daqui para lá, que têm permissão para atualizar o PMTU, para cada pacote TCP/IP!
Você pode detectar nós ao longo do caminho enviando um pacote daqui para lá, com o campo TTL (time-to-live) definido como 1, e registrar o host que retornou um erro "Pacote expirado", então definir o TTL como 2, 3, ... até obter uma resposta do destino real. E esse caminho pode mudar com o próximo pacote que você enviar.