Port Knocking: Autenticación a través de puertos cerrados. by MazarD http://www.mazard.info 1.-Introducción y teoria 2.-Código: Implementación tcp syn con timeout 3.-Problemas de la implementación tcp syn 4.-Despedida 1.-Introducción y teoria_____________________________________________________________________________________________ -Toc Toc! Me dejas entrar? -Contraseña! -Veeeeeenga, dejaameeee pasar. -Contraseña! Sino no te dejo entrar. -To to to toc toc, toc toc! -adelante :D Teoria explicada. Bueno va, mejor le damos un toque mas técnico. El port knocking es un método de autenticación que parte de la base y de la seguridad que nos dá el no tener ningún puerto abierto, esto nos aporta la seguridad de evitar DOS, DDOS y la explotación de cualquier tipo de bug por parte de un usuario desconocido. En cuanto al lado oscuro de la fuerza (que freek yo) tenemos que por ejemplo un rootkit puede estar a la escucha sin mantener un puerto abierto que pegue el cante a cualquier escaneo de puertos. Además dime que no es un estilazo autenticarte a un servidor con el nmap rollo: nmap -sS -T 2 -p 31337,6666,1111,1664 Pero como nos autenticamos si no podemos realizar ninguna conexion? El cliente deberá enviar paquetes tcp syn en cierto orden al servidor, el servidor sin dar ninguna respuesta irá monitorizando la sequencia, bien sea por el log del firewall, sniffando trafico de la red..., y cuando detecte una seqüencia correcta abrirá un puerto a la escucha acordado de antemano para que el cliente pueda conectar. A la sequencia correcta se le llama "knock". Por lo tanto el cliente para poder establecer la conexión necesitara conocer el knock correcto y el puerto que se abrirá al realizarlo. Como vemos el port knocking más que un método es una idea, a partir de aquí ya todo depende del ingenio y las paranoias del programador. En la web oficial de port knocking hay algunas implementaciones bastante curradas como una autenticación con md5 en un paquete udp, envio de icmp modificados para ejecutar cierta aplicación en el servidor... Después de esta pequeña explicación (creo que la idea es sencilla de enteder) vamos a lo que importa. PROGRAMAR, sea lo que sea, sea cuando sea. 2.-Código: Implementación tcp syn con timeout________________________________________________________________________ Yo cómo tenía más curiosidad que motivos para utilizar un sistema cómo éste he programado una implementación muy simple, se trata de la tcp syn con el pequeño añadido de un timeout por secuencia de knock. Por defecto windows hace 3 reintentos cuando una conexión falla, lo que puede cargarse nuestro knock, para solucionar esto modifica las siguientes claves del registro: [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters] "TcpMaxConnectRetransmissions"=dword:00000000 [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\VXD\MSTCP] "MaxConnectRetries"=dword:00000000 Vamos al código. Para entender ésto debes tener conocimientos sobre el uso de las librerias pcap, en mi caso sólo lo he testeado en windows con winpcap pero en linux debería funcionar también cambiando sólo las cabeceras.También es necesario un conocimiento suficientemente amplio sobre el protocolo tcp/ip. /*Port knocking implementación tcp syn Programado por MazarD MazarD@gmail.com http://www.mazard.info */ #include #include #define MaxSeq 5 #define Tout 100 void LlegadaPaquete(u_char *param, const struct pcap_pkthdr *pkt_header, const u_char *pkt_data); void Autentificado(void); typedef struct tIp { u_char Oct1; u_char Oct2; u_char Oct3; u_char Oct4; }tIp; pcap_dumper_t *Log=NULL; tIp *Knocker; u_int KnocksOk=0; u_int Knock[MaxSeq]; struct tm *TmAnt; int main() { pcap_if_t *Dispositivos; pcap_if_t *Dev; u_char Error[PCAP_ERRBUF_SIZE]; pcap_t *Handp; struct bpf_program fprog; int i=0; int entrada=0; u_char filtro[100]; u_char LogDir[50]; char Kcad[6]; pcap_findalldevs(&Dispositivos,Error); printf("MazarD Port Knocking Authentication\n\n"); printf("Interface:\n"); for (Dev=Dispositivos;Dev;Dev=Dev->next) { i++; printf("%d:%s\n",i,Dev->description); } if (i==0) { printf("Error:No devices found!\n"); pcap_freealldevs(Dispositivos); return 1; } scanf("%u",&entrada); if (entrada>i || entrada<1) { printf("Error:Wrong device!\n"); pcap_freealldevs(Dispositivos); return 1; } else { Dev=Dispositivos; for (i=1;inext; } //dev,paquete_entero,no promiscuo,refresh 1seg,errorbuff Handp=pcap_open_live(Dev->name,65536,0,1000,Error); if (Handp==NULL) { printf("Error:"); printf(pcap_geterr(Handp)); pcap_freealldevs(Dispositivos); return 1; } printf("Knock sequence:\n"); sprintf(filtro,"ip and tcp"); for (i=0;i<=MaxSeq-1;i++) { printf("Knock%d:",i); scanf("%s",&Kcad); Knock[i]=atoi(Kcad); if (i==0) { strcat(filtro," and dst port "); } else { strcat(filtro," or dst port "); } strcat(filtro,Kcad); } //if verbose printf("%s",filtro); //(1=optimize,0=netmask C, no broadcast capt) if (pcap_compile(Handp,&fprog,filtro,1,0)<0 || pcap_setfilter(Handp,&fprog)<0) { printf("Error:"); printf(pcap_geterr(Handp)); pcap_freealldevs(Dispositivos); pcap_close(Handp); return 1; } printf("Path for the log file(path\\\"nolog\"):"); scanf("%s",LogDir); if (strcmp(LogDir,"nolog")==0) { Log=pcap_dump_open(Handp,LogDir); printf("Logging on %s",LogDir); } //Sin final, sin usuario pcap_loop(Handp, 0, LlegadaPaquete, NULL); if (Log) pcap_dump_close(Log); pcap_close(Handp); return 0; } void LlegadaPaquete(u_char *user, const struct pcap_pkthdr *pkt_header, const u_char *pkt_data) { //u_int k; u_int LenIp,IniTcp; u_int FlagsTcp; u_short *PortK; tIp *NKnocker; tIp *Info; struct tm *Tstam; LenIp=pkt_data[14]; //Saltamos los 14 bytes de ethernet IniTcp=(LenIp & 0xF)*4; //len cabezera ip PortK=((u_short*) (pkt_data+14+IniTcp+2)); *PortK=ntohs(*PortK); FlagsTcp=pkt_data[14+IniTcp+13]; //Saltamos ethernet,ip tcp hasta flags Info=(tIp *) (pkt_data+30); if (FlagsTcp==0x0002) //syn { NKnocker=(tIp *) (pkt_data+30); Tstam=localtime(&pkt_header->ts.tv_sec); printf("Activity:%d.%d.%d.%d:%d\n",NKnocker->Oct1,NKnocker->Oct2,NKnocker->Oct3,NKnocker->Oct4,*PortK); if (*PortK==Knock[KnocksOk]) { if (KnocksOk!=0) { if (Tstam->tm_hour==TmAnt->tm_hour && Tstam->tm_min==TmAnt->tm_min && TmAnt->tm_sec-Tstam->tm_secOct1,NKnocker->Oct2,NKnocker->Oct3,NKnocker->Oct4); if (KnocksOk==4) { Autentificado(); } KnocksOk++; TmAnt=Tstam; } } else { printf("Knock TimeOut\n"); KnocksOk=0; } } else { printf("Knock %d Ok from:",KnocksOk); printf("%d.%d.%d.%d\n",NKnocker->Oct1,NKnocker->Oct2,NKnocker->Oct3,NKnocker->Oct4); Knocker=NKnocker; TmAnt=Tstam; KnocksOk++; } } else { if (Knocker==NKnocker) KnocksOk=0; } } if (Log) pcap_dump((unsigned char*)Log,pkt_header,pkt_data); } void Autentificado(void) { printf("Autentificado con exito!"); } 3.-Problemas del port knocking tcp syn_______________________________________________________________________________ Trabajando en mi implementación y estudiando las de algunos que he visto en la red, he encontrado el siguiente problema: Implementando un servicio para port knocking debemos comprobar que la secuencia de knock proviene siempre del mismo host, de otro modo el propio tráfico de la red podría darnos sequencias de knock inválidas. No es viable el mantener una lista de hosts que están intentando loguearse puesto que sería posible por un usuario malintencionado provocar un DDOS o como mínimo elevar el uso de nuestra memória y cpu hasta el extremo. Por lo tanto sólo nos queda que al recibir un knock inicial nuevo descartar la sequencia del host anterior o descartar el knock actual. Debido a esto un usuario un poco cabrón puede enviar paquetes syn indefinidamente al puerto inicial evitando la autenticación de cualquier usuario. La base del problema reside en que el programa en este punto no puede diferenciar el inicio de una sequencia válida a una que no lo es. Para solucionar éste problema lo mejor sería utilizar una implementación que tenga algún tipo de encriptación encapsulada en el paquete. 4.-Despedida_________________________________________________________________________________________________________ Vale, no es el mejor articulo sobre portkoncking de la red, pero a modo de introducción y con la poca info que hay en español yo creo que no está tan mal. Ya sabes, para cualquier duda, sugeréncia o chorrada contacta conmigo a través de mazard @ gmail . com Si te ha gustado el tema para más información consulta la web oficial sobre portknocking: http://www.portknocking.org/ Esta en inglés pero tiene muchisima información, códigos muy buenos y una explicación aunque en inglés, mas detallada que la que he dado en éste artículo. ___ ___ _________ _______ ______ |_ \ / _| /\ /_____ _/ /\ |_ __ | |_ __ \ | \ / | / \ / / / \ | |__| | | | \ \ ____|_|\ \/ /|_|____/ /__\_______/_/_____/__\ \___|__ __|__|_|___\ \___ \_______\ /_______/ /__________//___________\ \_____\ \__________/ /__/ _| | \/ | |__/ /____\ \ _/ /_____/ /____\ \_| | \ \___| |__/ / |___| |___/__________\/________/__________\__| \___|______/.info YES!! I walked through the dark ways of madness, and Im still alive!!! http://www.mazard.info MazarD [arroba] gmail [punto] com