Alterando los números de secuencia TCP
Fecha: 26 y 27 de mayo del 2020 (durante la cuarentena)
Escenario
Este laboratorio viene inspirado de un problema de tráfico entre dos servers separados por un firewall Cisco ASA, y en la
documentación del sistema operativo de uno de los servers se menciona un issue de TCP y NFS4 que puede deberse a la
alteración aleatoria de los números de secuencia TCP por parte del firewall.
Esto me llevó a dos cosas:
1.- Meditar si hay algun aviso por parte del firewall al origen sobre el número de secuencia a utilizar, porque de cambiarlo
“on the fly” el origen debe saberlo para numerar los siguientes segmentos. Pero esto deberia haberlo visto al menos una
vez en mi vida, o en algún libro. Quedó descartado.
2.- Que el firewall lleve una tabla de cada (y todas) sesión TCP con los valores inside y outside. Casi probable, falta probarlo.
Para verificar esto armé una maqueta con lo que tenía en casa: un PIX 501 (épico, con una marca de bala) y verificar si el
número de secuencia inside es diferente al outside. Y a los fierros me remití, no con NFS4 pero si con RDP.
Detalle de una sesión TCP ideal:
Decimos “ideal” por los números se secuencia y ACK fáciles de leer e interpretar, muy lejos de la realidad.
Fuente: madpackets.com
Explicación de la randomización del número de secuencia incial:
TCP sequence randomization—Each TCP connection
has two initial sequence numbers (ISN): one generated by the client
and one generated by the server. By default, the
ASA randomizes the ISN of the TCP SYN passing in both the inbound and
outbound directions. Randomization prevents
an attacker from predicting the next ISN for a new connection and potentially
hijacking the new session. You can disable
randomization per traffic class if desired
Fuente: cisco.com
Aunque dice que genera números aleatorios en inbound and outbound directions sólo pudimos demostrar random en una sola
dirección, tal vez se refiera a una sesión entrante y no a la de tráfico de retorno (ver punto 3.-)(el traffic-class que menciona al
final es el punto 4.1.-).
1.- Pruebas realizadas:
Se generó una conexión de escritorio remoto (RDP) entre la PC 192.168.0.10 (cliente) y 192.168.1.10 (servidor RDP) y con el
firewall en el medio, realizando NAT entre 192.168.0.10 y 192.168.1.20 y “randomizando” los números de secuencia TCP.
2.- Capturas de tráfico:
2.1.- Captura inside (pre firewall):
2.2- Captura outside (post firewall):
En esta captura vemos que el valor es el mismo, lo que da a sospecha de que Wiresahrk está mostrando números
“mas para humanos” que los reales.
Frame 1: 66 bytes on wire (528 bits), 66 bytes captured (528 bits) on
interface 0
Ethernet II, Src: 00:16:9d:da:82:13, Dst:
00:1b:38:7e:f1:71
Internet Protocol Version 4, Src: 192.168.1.20, Dst:
192.168.1.10
Transmission Control
Protocol, Src Port: 58382, Dst Port: 3389, Seq: 0, Len: 0
Source Port: 58382
Destination Port: 3389
[Stream index: 0]
[TCP Segment Len: 0]
Sequence number: 0 (relative sequence number) (esto es lo que hay que analizar)
[Next sequence number:
0 (relative sequence number)]
Acknowledgment number: 0
1000 ....
= Header Length: 32 bytes (8)
Flags: 0x002 (SYN)
Window size value: 64240
[Calculated window size:
64240]
Checksum: 0xbe37 [unverified]
[Checksum Status: Unverified]
Urgent pointer: 0
Options: (12 bytes), Maximum
segment size, No-Operation (NOP), Window scale
2.3.- Desactivamos la función Relative
sequence numbers:
By default Wireshark and TShark will keep track
of all TCP sessions and convert all Sequence Numbers (SEQ numbers) and
Acknowledge Numbers (ACK Numbers) into relative
numbers. This means that instead of displaying the real/absolute SEQ
and ACK numbers in the display, Wireshark will
display a SEQ and ACK number relative to the first seen segment for that
conversation.
This means that all SEQ and ACK numbers always start at 0 for the first packet seen
in each conversation.
This makes the numbers much smaller and easier
to read and compare than the real numbers which normally are initialized
to randomly selected numbers in the range 0 -
(2^32)-1 during the SYN phase.
Fuente: wireshark.org
2.4.- Captura inside (pre firewall):
En esta captura podemos ver la dirección IP origen y el número de secuencia original.
2.5.- Captura outside (post firewall):
En esta captura podemos ver la dirección IP origen “nateada” en 192.168.1.20 y el número de secuencia alterado.
2.6.- Comparación de cambios de #seq, de direcciones IP (NAT) y líneas
de tiempo:
3.- Verificación en el firewall:
Dentro de lo rudimentario del PIX 501 con versión 6.3, pude capturar la sesión TCP mediante debug. Con versiones mas nuevas o
con un ASA podemos realizar directamente una captura y analizarla con Wireshark.
3.1.- Activamos debug para ambas interfaces:
Firewall# debug
packet inside
Firewall# debug
packet outside
Firewall#
3.2.-
Paquete #1 (SYN
inside-outside):
--------- PACKET ---------
-- IP --
192.168.0.10 ==> 192.168.1.10 (paquete #1 en inside)
ver = 0x4 hlen = 0x5 tos = 0x0 tlen = 0x28
id = 0x6e12 flags = 0x40 frag off=0x0
ttl = 0x80 proto=0x6 chksum = 0xa4d
(valor en hexadecinal, en decimal es 3389)
-- TCP – |
source port = 0xe40e dest port = 0xd3dsyn (flag SYN)
seq = 0x8e0cf963 (valor en hexadecinal, en decimal es 2383214947)
ack = 0x0
(primer paquete, no
existe acuse de recibo)
hlen = 0x5 window = 0xfaf0
checksum = 0x828b urg = 0x0
tcp options:
0x1 0x3
0x3 0x8 0x1
0x1 0x4 0x2
0x1 0x1
0x4 0x2
--------- END OF PACKET ---------
--------- PACKET ---------
-- IP --
192.168.1.20 ==> 192.168.1.10 (paquete #1 en outside)
ver = 0x4 hlen = 0x5 tos = 0x0 tlen = 0x34
id = 0x6e12 flags = 0x40 frag off=0x0
ttl = 0x80
proto=0x6 chksum = 0x943
-- TCP --
source port = 0xe40e dest port = 0xd3dsyn
seq = 0xb6828afa (valor alterado por el firewall)
ack = 0x0
(primer paquete, no
existe acuse de recibo)
hlen = 0x8 window = 0xfaf0
checksum = 0xbe37 urg = 0x0
tcp options:
0x2 0x4
0x5 0x64 0x1
0x3 0x3 0x8
0x1 0x1
0x4 0x2
--------- END OF PACKET ---------
3.3.-
Paquete #2 (SYN ACK
outside-inside):
--------- PACKET ---------
-- IP --
192.168.1.10
==> 192.168.1.20 (paquete #2 en outside)
ver = 0x4 hlen = 0x5 tos = 0x0 tlen = 0x30
id = 0xf6
flags = 0x40 frag off=0x0
ttl = 0x80
proto=0x6 chksum = 0x7663
-- TCP --
source port = 0xd3d dest port = 0xe40esyn ack
seq = 0xc9f011bb (valor original)
ack = 0xb6828afb (corresponde a b6828afa +1)
hlen = 0x7 window = 0x2000
checksum = 0xd4d7 urg = 0x0
tcp options:
0x1 0x3
0x3 0x8 0x1
0x1 0x4 0x2
--------- END OF PACKET ---------
--------- PACKET ---------
-- IP --
192.168.1.10 ==> 192.168.0.10 (paquete #2 en inside)
ver = 0x4 hlen = 0x5 tos = 0x0 tlen = 0x30
id = 0xf6
flags = 0x40 frag off=0x0
ttl = 0x80
proto=0x6 chksum = 0x776d
-- TCP --
source port = 0xd3d dest port = 0xe40esyn ack
seq = 0xc9f011bb (valor original, no se modifica ya que fué creado en outside)
ack = 0x8e0cf964 (8e0cf963 + 1, será el próximo número de secuencia esperado por 192.168.1.10)
hlen = 0x7 window = 0x2000
checksum = 0x8fee urg = 0x0
tcp options:
0x1 0x3 0x3
0x8 0x1 0x1
0x4 0x2
--------- END OF PACKET ---------
3.4.-
Paquete #3 (ACK
inside-outside):
--------- PACKET ---------
-- IP --
192.168.0.10 ==> 192.168.1.10 (paquete #3 en inside)
ver = 0x4 hlen = 0x5 tos = 0x0 tlen = 0x28
id = 0x6e13 flags = 0x40 frag off=0x0
ttl = 0x80
proto=0x6 chksum = 0xa58
-- TCP --
source port = 0xe40e dest port = 0xd3dack
seq = 0x8e0cf964 (corresponde a 8e0cf963 + 1, que es el ACK enviado por 192.168.1.10)
ack = 0xc9f011bc (corresponde a c9f011bb +1)
hlen = 0x5 window = 0x200
checksum = 0xd705 urg = 0x0
-- DATA --
00000020: 00 00 00 00 00 00
30 | ......0
--------- END OF PACKET ---------
--------- PACKET ---------
-- IP --
192.168.1.20 ==> 192.168.1.10 (paquete #3 en outside)
ver = 0x4 hlen = 0x5 tos = 0x0 tlen = 0x28
id = 0x6e13 flags = 0x40 frag off=0x0
ttl = 0x80 proto=0x6 chksum = 0x94e
-- TCP --
source port = 0xe40e dest port = 0xd3dack
seq = 0xb6828afb (corresponde a b6828afa +1 y es el número esperado por 192.168.1.10)
ack = 0xc9f011bc (valor original, no se modifica ya que fué creado en outside)
hlen = 0x5 window = 0x200
checksum = 0x1bef urg = 0x0
--------- END OF PACKET ---------
3.5.- Verificación en el firewall de la sesión TCP:
Firewall# sh
conn
1 in use, 1 most used
TCP out 192.168.1.10:3389 in 192.168.0.10:58382
idle 0:00:21 Bytes 38 flags UIO
Firewall#
4.- Desactivando la función de alterar los números de secuencia TCP:
4.1.- En PIX y ASA con línea de comando mas actual y parecida a IOS la sintaxis es:
class-map TCP
match port tcp range 1 65535
!
policy-map global-policy
class TCP
set connection random-sequence-number disable
!
service-policy global_policy global
4.2.- En este PIX en particular que tiene un set de comandos viejo (algo áspero, casi mi favorito).
nat [(local_interface)] id local_ip [mask [dns]
[outside |[norandomseq] [max_conns [emb_limit]]]]
Firewall# conf
t
Firewall(config)# no static (inside,outside) 192.168.1.20 192.168.0.10 netmask
255.255.255.255
Firewall(config)# static (inside,outside) 192.168.1.20 192.168.0.10 netmask
255.255.255.255 norandomseq
Firewall(config)# exit
Firewall#
4.3.-
Verificación:
Firewall# sh
conn
1 in use, 1 most used
TCP out 192.168.1.10:3389 in 192.168.0.10:5036
idle 0:00:10 Bytes 38 flags UIO
Firewall#
4.4.- Verificación de la captura de tráfico:
5.- Configuración del equipo:
Firewall# sh runn (sólo lo mas
importante)
: Saved
:
PIX Version 6.3(5)
interface ethernet0 auto
interface ethernet1 100full
nameif ethernet0 outside security0
nameif ethernet1 inside security100
hostname Firewall
mtu outside 1300
mtu inside 1500
ip address outside 192.168.1.1 255.255.255.0
ip address inside 192.168.0.1 255.255.255.0
static (inside,outside) 192.168.1.20
192.168.0.10 netmask 255.255.255.255 0 0
timeout xlate 3:00:00
timeout conn 1:00:00 half-closed 0:10:00
udp 0:02:00 rpc 0:10:00 h225 1:00:00
dhcpd address 192.168.0.10-192.168.0.11 inside
dhcpd lease 3600
dhcpd ping_timeout 750
dhcpd enable inside
Cryptochecksum:d2a7592c51622808c2959c2c4acfaf30
: end
Firewall#
6.- El libro con el que me inicié en el
2002 y el PIX 501 con la marca de bala:
(2020) Networking for alien minds
Rosario, Argentina