Problema: La regla ip creada para enrutar el tráfico L4 hacia una interfaz específica no se respeta cuando los paquetes se generan con una dirección de origen diferente.
Descripción general Quiero generar paquetes con una dirección de origen diferente a la dirección del host. Para lograr esto, estoy usando el paquete Scapy de Python. Nota: mi objetivo es enviar para enviar tráfico DNS, sin embargo, no pude encontrar una solución simple que me permita falsificar la dirección de origen en las solicitudes de DNS, por lo que solo estoy generando un paquete UDP con la dirección src y dst en el puerto 53. Creo que esto todavía funciona ya que solo estoy probando L3 y L4, no el protocolo DNS real en este momento. Aquí está mi guión
#!/usr/bin/python3
# The following is designed to generate a packet with a different source address
import sys
from scapy.all import *
def main():
S = "10.0.26.122" # spoofed source IP address
D = "10.0.26.123" # destination IP address
SP = 53 # source port
DP = 53 # destination port
payload = "This is a fake message" # packet payload
spoofed_packet = IP(src=S, dst=D) / UDP(sport=53, dport=53) / payload
send(spoofed_packet)
#Entry point
main()
Antes de ejecutar el script, así es como se ve mi tabla de rutas:
# route -n
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
0.0.0.0 10.104.8.1 0.0.0.0 UG 101 0 0 ens192
10.0.21.0 0.0.0.0 255.255.255.0 U 104 0 0 ens256
10.0.26.0 0.0.0.0 255.255.255.0 U 0 0 0 ens224
10.0.27.0 0.0.0.0 255.255.255.0 U 102 0 0 ens193
10.0.28.0 10.0.29.1 255.255.255.0 UG 100 0 0 ens161
10.0.29.0 0.0.0.0 255.255.255.0 U 100 0 0 ens161
10.104.8.0 0.0.0.0 255.255.255.0 U 101 0 0 ens192
10.212.134.0 10.104.8.1 255.255.255.0 UG 101 0 0 ens192
192.168.122.0 0.0.0.0 255.255.255.0 U 0 0 0 virbr0
Aquí están las interfaces ip.
# ip -br a
lo UNKNOWN 127.0.0.1/8
ens161 UP 10.0.29.122/24
ens192 UP 10.104.8.122/24
ens193 UP 10.0.27.122/24
ens224 UP 10.0.26.122/24
ens256 UP 10.0.21.122/24
virbr0 DOWN 192.168.122.1/24
virbr0-nic DOWN
ip_vti0@NONE DOWN
Cuando ejecuto el script, ./packet-gen.py "10.0.26.122" "10.0.26.123"
funciona. Esto se debe a que todavía no he creado mi regla de IP/tabla de enrutamiento separada. Realizo un tcpdump en el host (10.0.26.122) y en el host del otro extremo (10.0.26.123) y veo que se envía el paquete UDP. También probé dig www.google.com @10.0.26.123
y vi que se estaba realizando una solicitud de DNS real y obtuve una respuesta.
Ahora el problema. Quiero eliminar la entrada de ruta en la tabla principal y luego solo la ruta según el número de puerto. Para hacer esto ejecuto lo siguiente para eliminar primero la entrada de ruta a 10.0.26.0/24.
# ip route del 10.0.26.0/24 dev ens224
# route -n
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
0.0.0.0 10.104.8.1 0.0.0.0 UG 101 0 0 ens192
10.0.21.0 0.0.0.0 255.255.255.0 U 104 0 0 ens256
10.0.27.0 0.0.0.0 255.255.255.0 U 102 0 0 ens193
10.0.28.0 10.0.29.1 255.255.255.0 UG 100 0 0 ens161
10.0.29.0 0.0.0.0 255.255.255.0 U 100 0 0 ens161
10.104.8.0 0.0.0.0 255.255.255.0 U 101 0 0 ens192
10.212.134.0 10.104.8.1 255.255.255.0 UG 101 0 0 ens192
192.168.122.0 0.0.0.0 255.255.255.0 U 0 0 0 virbr0
Se elimina la entrada. Si ejecuto mi script nuevamente, no funciona. La solicitud de excavación también falla. Esto es de esperarse ya que no hay una ruta L3 en la tabla de enrutamiento del núcleo principal.
Para enrutar en L4, primero creé una nueva tabla de rutas IP para enviar todo el tráfico a través de ens224:
# ip route add table 53 0.0.0.0/0 dev ens224
Luego creo una regla de IP para capturar cualquier tráfico usando el puerto 53 y envío mi tabla personalizada 53.
# ip rule add ipproto udp dport 53 lookup 53
También creé una regla sysctl especial para rp_filter y relajé demasiado las reglas estrictas de reenvío de ruta inversa.
# sysctl -w "net.ipv4.conf.ens224.rp_filter=2"
Para comprobar mi trabajo veo lo siguiente:
# ip route list table 53
default dev ens224 scope link
# ip rule list
0: from all lookup local
32765: from all ipproto udp dport 53 lookup 53
32766: from all lookup main
32767: from all lookup default
# ip route get 10.0.26.123 ipproto udp dport 53
10.0.26.123 dev ens224 table 53 src 10.0.26.122 uid 0
cache
# ip route get 10.0.26.123
10.0.26.123 via 10.104.8.1 dev ens192 src 10.104.8.122 uid 0
cache
El último comando muestra que, de forma predeterminada, si la comunicación no es dns, use la ruta predeterminada.
Para probar esto, primero intento hacer ping a 10.0.26.123. Falla lo que se esperaba. Ahora intento realizar una solicitud de excavación dig www.google.com @10.0.26.123
y funciona. La solicitud de excavación alcanza la regla ip antes de ir a la tabla principal y se enruta adecuadamente. Veo que el tráfico llega al servicio con tcpdump (10.0.26.123) y proviene de mi host (10.0.26.122).
Ahora intento ejecutar mi script scapy nuevamente y nada. Incluso con la misma dirección de origen que el host, no hay nada en tcpdump en mi host o en el servidor. Intenté cambiar la dirección de origen, no hubo cambios, nada. Si vuelvo a agregar la ruta principal L3 para 10.0.26.0/24 en la tabla principal, el script scapy vuelve a funcionar. ¿Que me estoy perdiendo aqui? ¿Por qué mi tráfico generado no respeta los conjuntos de reglas de IP que creé?
Respuesta1
Scapy no utiliza el mecanismo de enrutamiento del sistema operativo, sino que utiliza su propia tabla de enrutamiento ( conf.route
objeto), sincronizada desde la tabla de enrutamiento del sistema operativo cuando se inicia Scapy (o cada vez que conf.route.resync()
se llama al método).
El mecanismo de enrutamiento de Scapy no admite el enrutamiento de origen, lo que explica el comportamiento que usted describe.