Solución de la tarea con pwnable.kr 07 - input. Entendiendo pwntools

imagen

En este artículo, analizaremos la solución de una tarea de varios niveles utilizando la biblioteca pwntools .

Información organizacional
Especialmente para aquellos que quieran aprender algo nuevo y desarrollarse en cualquiera de las áreas de información y seguridad informática, escribiré y hablaré sobre las siguientes categorías:

  • PWN;
  • criptografía (criptografía);
  • tecnologías de red (Red);
  • inversa (ingeniería inversa);
  • esteganografía (Stegano);
  • búsqueda y explotación de vulnerabilidades WEB.

Además de esto, compartiré mi experiencia en informática forense, análisis de malware y firmware, ataques a redes inalámbricas y redes de área local, realización de pentests y escritura de exploits.

Para que pueda conocer nuevos artículos, software y otra información, creé un canal en Telegram y un grupo para discutir cualquier problema en el campo de ICD. Además, consideraré personalmente sus solicitudes personales, preguntas, sugerencias y recomendaciones personalmente y responderé a todos .

Toda la información se proporciona solo con fines educativos. El autor de este documento no tiene ninguna responsabilidad por los daños causados ​​a alguien como resultado del uso de los conocimientos y métodos obtenidos como resultado de estudiar este documento.

Solución de trabajo de entrada


Hacemos clic en el icono con la entrada de la firma y se nos dice que debemos conectarnos a través de SSH con la contraseña de invitado.

imagen

Cuando está conectado, vemos el banner correspondiente.

imagen

Veamos qué archivos hay en el servidor y qué derechos tenemos.

ls -l 

imagen

Por lo tanto, podemos leer el código fuente del programa, ya que existe el derecho de leer para todos y ejecutar el programa de entrada con los derechos del propietario (se establece el bit fijo). Veamos el resultado del código.

Código fuente input.c
 #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/socket.h> #include <arpa/inet.h> int main(int argc, char* argv[], char* envp[]){ printf("Welcome to pwnable.kr\n"); printf("Let's see if you know how to give input to program\n"); printf("Just give me correct inputs then you will get the flag :)\n"); // argv if(argc != 100) return 0; if(strcmp(argv['A'],"\x00")) return 0; if(strcmp(argv['B'],"\x20\x0a\x0d")) return 0; printf("Stage 1 clear!\n"); // stdio char buf[4]; read(0, buf, 4); if(memcmp(buf, "\x00\x0a\x00\xff", 4)) return 0; read(2, buf, 4); if(memcmp(buf, "\x00\x0a\x02\xff", 4)) return 0; printf("Stage 2 clear!\n"); // env if(strcmp("\xca\xfe\xba\xbe", getenv("\xde\xad\xbe\xef"))) return 0; printf("Stage 3 clear!\n"); // file FILE* fp = fopen("\x0a", "r"); if(!fp) return 0; if( fread(buf, 4, 1, fp)!=1 ) return 0; if( memcmp(buf, "\x00\x00\x00\x00", 4) ) return 0; fclose(fp); printf("Stage 4 clear!\n"); // network int sd, cd; struct sockaddr_in saddr, caddr; sd = socket(AF_INET, SOCK_STREAM, 0); if(sd == -1){ printf("socket error, tell admin\n"); return 0; } saddr.sin_family = AF_INET; saddr.sin_addr.s_addr = INADDR_ANY; saddr.sin_port = htons( atoi(argv['C']) ); if(bind(sd, (struct sockaddr*)&saddr, sizeof(saddr)) < 0){ printf("bind error, use another port\n"); return 1; } listen(sd, 1); int c = sizeof(struct sockaddr_in); cd = accept(sd, (struct sockaddr *)&caddr, (socklen_t*)&c); if(cd < 0){ printf("accept error, tell admin\n"); return 0; } if( recv(cd, buf, 4, 0) != 4 ) return 0; if(memcmp(buf, "\xde\xad\xbe\xef", 4)) return 0; printf("Stage 5 clear!\n"); // here's your flag system("/bin/cat flag"); return 0; } 


Del código se deduce que necesitamos pasar por cinco niveles. Los tomaremos por turno.

imagen

En el primer nivel, se verifica que el número de argumentos del programa es 100. En este caso, el elemento 65 debería ser la cadena "\ x00", y el elemento 66 debería ser "\ x20 \ x0a \ x0d". Cree su propio directorio en el directorio / tmp / y cree un script Python allí.

imagen

Para resolver el primer nivel, crearemos una matriz de cien líneas de 'A'. Y asigne los argumentos necesarios a los valores deseados. Podemos comenzar el proceso con estos argumentos de la siguiente manera:

 from pwn import * a = ['A']*100 a[0] = '/home/input2/input' a[ord('A')] = '\x00' a[ord('B')] = '\x20\x0a\x0d' ex = process(argv=a) ex.interactive() 

imagen

Pasamos el primer nivel. Echa un vistazo a la segunda.

imagen

En este nivel, se leen dos líneas, una de la entrada estándar stdin y la otra de stderr. Necesitamos crear dos archivos que contendrán estas líneas.

imagen

Abra las secuencias en estos archivos y especifique el descriptor para la secuencia de un archivo como el stdin del descriptor y otro archivo como el stderr del descriptor.

 from pwn import * a = ['A']*100 a[0] = '/home/input2/input' a[ord('A')] = '\x00' a[ord('B')] = '\x20\x0a\x0d' fin = open('/tmp/ex/in.txt', 'r') ferr = open('/tmp/ex/err.txt', 'r') ex = process(argv=a, stdin=fin, stderr=ferr) fin.close() ferr.close() ex.interactive() 

imagen

Procedemos a la decisión del tercer nivel.

imagen

La función getenv () devuelve el valor de una variable de entorno, que debería ser igual al valor de referencia. Por lo tanto, debe crear una variable de entorno con un valor específico.

 from pwn import * a = ['A']*100 a[0] = '/home/input2/input' a[ord('A')] = '\x00' a[ord('B')] = '\x20\x0a\x0d' fin = open('/tmp/ex/in.txt', 'r') ferr = open('/tmp/ex/err.txt', 'r') e={'\xde\xad\xbe\xef':'\xca\xfe\xba\xbe'} ex = process(argv=a, stdin=fin, stderr=ferr, env=e) fin.close() ferr.close() ex.interactive() 

imagen

Manejamos la variable de entorno, ahora comencemos desde el cuarto nivel.

imagen

Según el código, podemos decir que el programa abre un archivo con el nombre "\ x0a" y lee 4 caracteres, luego de lo cual los compara con los bytes "\ x00". Dado que tanto los propios caracteres como el nombre del archivo consisten en caracteres no imprimibles, utilizamos python.

imagen

imagen

El último nivel permanece. Empecemos

imagen

El programa abre el socket en el puerto especificado en el argumento 66. Luego recibe 4 bytes a través de la red y lo compara con la cadena de referencia. Necesitamos agregar otro argumento al programa: el número de puerto, establecer una conexión y enviar los 4 bytes necesarios.

 from pwn import * a = ['A']*100 a[0] = '/home/input2/input' a[ord('A')] = '\x00' a[ord('B')] = '\x20\x0a\x0d' a[ord('C')] = '1234' fin = open('/tmp/ex/in.txt', 'r') ferr = open('/tmp/ex/err.txt', 'r') e={'\xde\xad\xbe\xef':'\xca\xfe\xba\xbe'} ex = process(argv=a, stdin=fin, stderr=ferr, env=e) fin.close() ferr.close() ex.interactive() 

imagen

imagen

Eso es todo, consigue tus puntos.

imagen

¡Nos vemos en los siguientes artículos!

Estamos en un canal de telegramas: un canal en Telegramas .

Source: https://habr.com/ru/post/460249/


All Articles