He estado investigando cómo conseguir llegar a inyectar lo que yo quiera en el cable de red, y con esto me refiero a que por el cable vaya una ristra de bytes tal cual yo la he definido, sin más cabeceras ni información añadida por ningún driver, ni SO y lo he logrado.
Como muchos saben en sistemas POSIX existe o podría existir la llamada al sistema socket(domain, type, protocol), que permite iniciar un socket para la comunicación por red. Siempre la he mirado con mucho recelo porque aunque me permite una gran flexibilidad, lo máximo que yo sabía de a dónde podía llegar es a actuar por encima del nivel de red, concretamente por encima de IP mediante SOCK_RAW.
Hoy he descubierto, después de mirar mucho código, de leer mucho man y buscar en internet, que se puede llegar mas lejos (como suponía) y he logrado acceder totalmente a la red.
En el man socket se especifica el domain AF_PACKET para acceder al bajo nivel, también se comenta consultar packet(7). Ese es el dominio que hace falta para acceder a bajo nivel, en el siguiente man nos comentan que existe un type SOCK_RAW que nos permite acceder al driver ¡sin que este añada cabeceras de ningún tipo!. Pero no todo está hecho, hay que aprender a usar todo esto. El siguiente codigo es un ejemplo:
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
int main(int argc, char *argv[]) {
char *buf = "Hola\0";
int fd, c;
struct ifreq ifr;
struct sockaddr_ll sa;
fd = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
if (fd < 0) {
fprintf(stderr, "socket fail\n");
exit(-1);
}
memset(&ifr, 0, sizeof(ifr));
strncpy(ifr.ifr_name, "eth0", strlen("eth0"));
if (ioctl(fd, SIOCGIFINDEX, &ifr) < 0) {
fprintf(stderr, "ioctl fail\n");
exit(-1);
}
sa.sll_family = AF_PACKET;
sa.sll_ifindex = ifr.ifr_ifindex;
sa.sll_protocol = htons(ETH_P_ALL);
c = sendto(fd, buf, strlen(buf), 0, (struct sockaddr *)&sa, sizeof(sa));
if (c < 0) {
fprintf (stderr, "write fail\n");
exit(-1);
}
exit(0);
}
Primero hay que abrir el socket con las características especificadas, luego nos tenemos que enterar mediante el uso de ioctl cual es el index de la interfaz que queremos usar (eth0 en este caso). Ese número es el identificador de interfaces que ha reconocido el SO, piensen que al abrir el socket no se le especifica en ningún lado en que tarjeta debería escribir y leer, de hecho es independiente del socket. Eso se especifica en cada lectura y cada escritura como vemos en la llamada a sendto. Se ha preparado una estructura struct sockaddr_ll (ya conocen los struct sockaddr, este es el _ll link layer ;), en el campo sll_ifindex que averiguamos previamente con ioctl.
Evidentemente sobra decir que para que ese código funcione hay que ejecutarlo con permisos de root o, como documenta el manual, con CAP_NET_RAW.
Pues eso, así es como se inyecta directamente y sin pasar por bibliotecas como libnet, sino yendo directamente a los servicios del SO.
Happy hacking!
1 comentario:
Es una putada esto de que intente interpretar codigos xml y no se vea que bibliotecas he usado xD.
Bueno, cualquiera de ustedes sabra buscar cuales hacen falta... unistd, stdlib, stdio, string, netpacket/packet...
Suerte :P
Publicar un comentario