Ir al contenido


Foto

Servidor para la Shell inversa de seoane


  • Por favor identifícate para responder
6 respuestas en este tema

#1 escafandra

escafandra

    Advanced Member

  • Administrador
  • 4.107 mensajes
  • LocationMadrid - España

Escrito 01 febrero 2015 - 06:09

En un rato libre decidí escribir un servidor para la shell inversa de seoane, visto que proponía usar ncat como servidor.

El programa es una aplicación de consola que simula un intérprete de comandos. Recibe como parámetro el puerto de escucha, que deberá coincidir con el del programita de seoane.

Como las cadenas devueltas por la shell inversa pueden ser muy largas y no hay garantía de que llegue todo en un mismo paquete, se precisa un bucle de lectura del socket hasta que no quede nada en la cola, así como colocar un timeout en recv.

He encontrado un asunto engorroso a la hora de tratar el comando "cls" ya que la consola devuelve una cadena de esta forma: 'cls'+#10+#12+#13+#10. El carácter 12 (nueva página) es imprimible pero no es alfanumérico quedando fea su representación en pantalla, he decidido gestionarlo eliminando toda la cadena devuelta exceptuando el último retorno de línea, a imagen y semejanza del intérprete de comandos.

Aunque el shell inverso que escribió seoane funciona a la perfección con este servidor, me he permitido la licencia de hacer pequeños cambios para que se quede a la espera de la conexión, en caso de que el servidor no esté en marcha, y para que detecte la caída del mismo, cierre la consola y vuelva a quedar a la espera de otra conexión. De otra forma quedarían múltiples procesos cmd.exe abiertos en segundo plano. Los cambios realizados son mínimos, quedando muy fiel al código original. la shell inversa se cierra enviando el comando "exit"

El código del servidor es el siguiente:


delphi
  1. program Server;
  2.  
  3. {$APPTYPE CONSOLE}
  4.  
  5. uses
  6.   Windows, SysUtils, Winsock;
  7.  
  8.  
  9. const
  10.   BufferSize = 1024;
  11.   cls = 'cls'+#10+#12+#13+#10;
  12.  
  13. // Borar pantalla de consola
  14. procedure clrscr;
  15. var
  16.   ConSize: DWORD;
  17.   ConInfo: CONSOLE_SCREEN_BUFFER_INFO;
  18.   ConPos : TCOORD;
  19.   hConsole: THANDLE;
  20.   CharsWritten: DWORD;
  21. begin
  22.   hConsole:= getstdhandle(STD_OUTPUT_HANDLE);
  23.   if getconsolescreenbufferinfo(hConsole, ConInfo) then
  24.   begin
  25.     ConPos.x := 0;
  26.     ConPos.y := 0;
  27.     ConSize := ConInfo.dwsize.x * ConInfo.dwsize.y;
  28.     if FillConsoleOutputCharacter(hConsole, ' ', ConSize, ConPos, CharsWritten) then
  29.       if GetConsoleScreenBufferInfo(hConsole, ConInfo) then
  30.         if FillConsoleOutputAttribute(hConsole, ConInfo.wAttributes, ConSize, ConPos, CharsWritten) then
  31.           SetConsoleCursorPosition(hConsole, ConPos);
  32.   end;
  33. end;
  34.  
  35. // Recibe datos de la consola remota
  36. function Recibe(Sock: TSOCKET; Input: String): integer;
  37. var
  38.   Buffer, clsBuffer: PCHAR;
  39.   Len, clsLen: integer;
  40.   TimeOut: DWORD;
  41. begin
  42.   GetMem(Buffer, BufferSize);
  43.   Result:= 0;
  44.   TimeOut:= 1000;
  45.   setsockopt(Sock, SOL_SOCKET, SO_RCVTIMEO, PCHAR(@TimeOut), sizeof(TimeOut));
  46.  
  47.   // Leo hasta que no quede nada
  48.   repeat
  49.     Len:= recv(Sock, Buffer^, BufferSize-1, 0);
  50.     if Len > 0 then
  51.     begin
  52.       CharToOemBuff(Buffer, Buffer, Len);
  53.       // Si recibo cls borro la pantalla
  54.       if StrLIComp(Buffer, 'cls', 3) = 0 then
  55.       begin
  56.         // La cadena cls tiene 7 caracteres, si no se leyó entera sigo leyendo
  57.         // 'cls'+#10+#12+#13+#10;
  58.         clsBuffer:= Buffer;
  59.         clsLen:= Len;
  60.         while clsLen < 7 do
  61.         begin
  62.           inc(clsBuffer, Len);
  63.           Len:= recv(Sock, clsBuffer^, BufferSize - clsLen - 1, 0);
  64.           clsLen:= clsLen + Len;
  65.         end;
  66.         Len:= clsLen;
  67.         Buffer[Len]:= #0; // la cadena debe terminar en cero
  68.         if StrLIComp(Buffer, cls, 7) = 0 then clrscr;
  69.         Write(String(Buffer + 6));
  70.       end
  71.       // Si es exit salimos
  72.       else
  73.       if StrLIComp(PCHAR(Input), 'exit', 4) = 0 then break
  74.       // Imprimimos la cadena
  75.       else
  76.       begin
  77.         Buffer[Len]:= #0;  // la cadena debe terminar en cero
  78.         if Result = 0 then Write(String(Buffer + length(Input)))
  79.         else Write(String(Buffer));
  80.       end;
  81.       Result:= Result + Len;
  82.     end;
  83.   until (Len <= 0);
  84.   FreeMem(Buffer);
  85. end;
  86.  
  87. var
  88.   Wsa: TWSADATA;
  89.   Sock_e: TSOCKET;  // Sock de escucha
  90.   Sock_c: TSOCKET;  // Sock de comunicación
  91.   TimeOut: DWORD;
  92.   ServerAddr, ClientAddr: sockaddr_in;
  93.   Len: integer;
  94.   Port: WORD;
  95.   Input: String;
  96. begin
  97.   Port:= StrToIntDef(ParamStr(1), 55555);
  98.   Len:= 0;
  99.   Input:= '';
  100.  
  101.   // Inicializamos
  102.   Writeln('Inicializando el servidor...'+#10);
  103.   if WSAStartup(MAKEWORD(2, 0), Wsa) <> 0 then exit;
  104.  
  105.   //Creamos el socket
  106.   Sock_e:= socket(AF_INET, SOCK_STREAM,IPPROTO_TCP);
  107.   if Sock_e <> INVALID_SOCKET then
  108.   begin
  109.     // Dirección IP y puerto
  110.     ServerAddr.sin_family:= AF_INET;
  111.     ServerAddr.sin_addr.s_addr:= INADDR_ANY;
  112.     ServerAddr.sin_port:= htons(Port);
  113.  
  114.     // Asociamos el socket al puerto
  115.     if bind(Sock_e, ServerAddr, sizeof(ServerAddr)) <> -1 then
  116.     begin
  117.       // Bucle principal del servidor
  118.       // Este servidor nunca termina, siempre escuchará
  119.       while true do
  120.       begin
  121.         // Escuchando puerto
  122.         WriteLn('Escuchando por el puerto ', Port);
  123.         if listen(Sock_e, 1) <> -1 then
  124.         begin
  125.           //hay una conexión entrante y la aceptamos
  126.           Len:= sizeof(sockaddr_in);
  127.           Sock_c:= accept(Sock_e, @ClientAddr, @Len);
  128.           if Sock_c = INVALID_SOCKET then continue;
  129.           windows.Beep(1000, 100);
  130.           WriteLn('Shell inversa conectada'+#10+#10);
  131.           // Bucle de comunicación
  132.           repeat
  133.             // Leemos los datos entrantes
  134.             if (Recibe(Sock_c, Input) = 0) then break;//recibimos los datos que envie
  135.             // Escribimos comandos
  136.             ReadLn(Input); Input:= Input+#10;
  137.             TimeOut:= 1000;
  138.             setsockopt(Sock_c, SOL_SOCKET, SO_SNDTIMEO, PCHAR(@TimeOut), sizeof(TimeOut));
  139.             send(Sock_c, PCHAR(Input)^, Length(Input), 0);
  140.           until false;
  141.           windows.Beep(1000, 200);
  142.           WriteLn(#10+'Cliente Desconectado'+#10);
  143.           closesocket(Sock_c);
  144.         end; // listen
  145.       end; // While (true)
  146.       closesocket(Sock_e);
  147.     end; // if bind
  148.   end; // if Sock_e
  149.   WSACleanup;
  150. end.


Esto sólo pretende ser un juguete funcional y muy mejorable

El código de la shell inversa lo tenéis en la página de seoane

Subo los fuentes y binarios de la shell inversa modificada y del servidor.



Saludos.
  • 0

#2 Wilson

Wilson

    Advanced Member

  • Moderadores
  • PipPipPip
  • 2.137 mensajes

Escrito 01 febrero 2015 - 08:05

Como de costumbre un aporte de lujo.

Un cordial saludo maestro.
  • 0

#3 escafandra

escafandra

    Advanced Member

  • Administrador
  • 4.107 mensajes
  • LocationMadrid - España

Escrito 02 febrero 2015 - 08:46

Gracias, Wilson.

He hecho una pequeña modificación para gestionar mejor el comando "exit"


Saludos.
  • 0

#4 seoane

seoane

    Advanced Member

  • Administrador
  • 1.259 mensajes
  • LocationEspaña

Escrito 02 febrero 2015 - 09:15

;) Vaya, vaya ... que maldad andaras planeando amigo escafandra  :D

Excelente codigo  :ap:



  • 0

#5 escafandra

escafandra

    Advanced Member

  • Administrador
  • 4.107 mensajes
  • LocationMadrid - España

Escrito 02 febrero 2015 - 09:29

;) Vaya, vaya ... que maldad andaras planeando amigo escafandra  :D

Excelente codigo  :ap:


No planeo mas maldad que la que he publicado, si eso es una maldad...

En realidad la maldad hace tiempo que la hice y no con ese código, sino con algo más sofisticado que una shell inversa, la cual incluía también.  Cosas para no decir en público. *-)


Saludos.
  • 0

#6 egostar

egostar

    missing my father, I love my mother.

  • Administrador
  • 14.448 mensajes
  • LocationMéxico

Escrito 03 febrero 2015 - 10:35

Como siempre, los amigos del API hacen de las suyas :) y uno sólo se queda como el chinito, "nomas milando" :D :D :D

Saludos
  • 0

#7 escafandra

escafandra

    Advanced Member

  • Administrador
  • 4.107 mensajes
  • LocationMadrid - España

Escrito 03 febrero 2015 - 12:18

Como siempre, los amigos del API hacen de las suyas :) y uno sólo se queda como el chinito, "nomas milando" :D :D :D


Bueno, siempre puedes usar ambos programas para controlar remotamente la shell de otro PC, es de gran utilidad.  ;)


Saludos.
  • 0




IP.Board spam blocked by CleanTalk.