Hace unos años cuando empecé a trastear con Android y animado por mi afición a la Ingeniería Inversa, decidí realizar una serie de crackmes. Los dos primeros pasaron algo desapercibidos, pero el Crackme nº3 tuvo una gran repercusión en el mundillo y, aunque no fue el primer crackme para Android ni mucho menos, si que fue uno de los más estudiados. Todos ellos fueron publicados a través de crackmes.de y el nº3 en cuestión el 6 de Noviembre de 2010. Os dejo una lista de unas cuantas webs donde aparece analizado para que veáis la repercusión que a mi parecer tuvo.

Soluciones al crackme

Referencias al crackme

Links


Introducción Aquí tenemos un CrackMe diferente a lo que estamos acostumbrados, ya que en vez del típico número de serie
Warning: This challenge is still active and therefore should not be resolved using this information. Aviso: Este reto sigue en
Acabo de montar AperiSolve en una Raspi que tenía por casa pensando que sería coser y cantar, pero me he
Introducción Este es un crackme hecho en .Net con dos Nags a parchear y un algoritmo muy sencillo pero que

Introducción

Aquí tenemos un CrackMe diferente a lo que estamos acostumbrados, ya que en vez del típico número de serie asociado a un nombre la comprobación se realiza mediante checkboxes con una matriz de 7×3. El CrackMe está realizado en Visual C++ lo que facilita en parte encontrar rápidamente la rutina de comprobación.

Comprobación

004013C5   > /8B7424 10     MOV     ESI,[DWORD SS:ESP+10]						;
004013C9   . |33FF          XOR     EDI,EDI
004013CB   > |8B86 74304000 MOV     EAX,[DWORD DS:ESI+403074]                   ;
004013D1   . |8BCB          MOV     ECX,EBX
004013D3   . |50            PUSH    EAX
004013D4   . |E8 6F020000   CALL    <JMP.&MFC42.#3092_CWnd::GetDlgItem>			; Lee el estado del checkbox
004013D9   . |8B48 20       MOV     ECX,[DWORD DS:EAX+20]
004013DC   . |6A 00         PUSH    0
004013DE   . |6A 00         PUSH    0
004013E0   . |68 F0000000   PUSH    0F0
004013E5   . |51            PUSH    ECX                                         ; 
004013E6   . |FFD5          CALL    NEAR EBP
004013E8   . |3B86 20304000 CMP     EAX,[DWORD DS:ESI+403020]					; Comprueba el estado del checkbox (1 activado 0 desactivado)
004013EE   . |75 20         JNZ     SHORT Matrix_C.00401410						; Salto a chico malo
004013F0   . |47            INC     EDI											; Incrementa contador
004013F1   . |83C6 04       ADD     ESI,4
004013F4   . |83FF 07       CMP     EDI,7										; ¿Hemos terminado de leer las columnas? ¿contador = 7?
004013F7   .^|7C D2         JL      SHORT Matrix_C.004013CB                     ; si terminan las columnas deja pasar
004013F9   . |8B4424 10     MOV     EAX,[DWORD SS:ESP+10]
004013FD   . |83C0 1C       ADD     EAX,1C										; contador de filas
00401400   . |83F8 54       CMP     EAX,54										; 3 filas = 1C+1C+1C=54
00401403   . |894424 10     MOV     [DWORD SS:ESP+10],EAX
00401407   .^\7C BC         JL      SHORT Matrix_C.004013C5						; ¿Hemos terminado de leer la fila? ¿contador = 54?
00401409   .  68 D8304000   PUSH    Matrix_C.004030D8                           ;  ASCII "Registration successful!"
0040140E   .  EB 05         JMP     SHORT Matrix_C.00401415
00401410   >  68 C8304000   PUSH    Matrix_C.004030C8                           ;  ASCII "Not registered!"

En la rutina de comprobación se ve fácil un CMP EDI,7 por lo que podemos deducir que si el creador no se ha molestado mucho la comprobación se realiza de izquierda a derecha y de arriba hacia abajo.

Orden de comprobación

Tal es así que si ponemos un breakpoint en 4013E8, podemos ir sacando el estado correcto de los checkboxes sin mucha molestia.

Resultado final

Enlaces

Warning: This challenge is still active and therefore should not be resolved using this information.
Aviso: Este reto sigue en activo y por lo tanto no se debería resolver utilizando esta información.

Introducción

Realistic Challenge 3: Your school is employing a web designer who is charging far too much for site design and doesn’t know anything about protecting the site. However, he’s sure that there’s no way anyone can hack into any site he’s designed, prove him wrong!
 En tu escuela están haciendo una web nueva muy rápido. El creador asegura que no le pueden hackear, demuéstrale que está equivocado.

Analizando a la víctima

Echamos un vistazo y vemos en el menú cosas interesantes. La primera de ellas es un Login que pronto descartamos ya que no parece llevar a ninguna parte. La segunda sirve para mandar enlaces al administrador y que este los publique posteriormente en la web.
Vamos a trastear un poco con la opción de mandar enlaces. En el código fuente ya vemos algo interesante y es que hay un campo oculto con el valor a 1 al mandar el enlace. Probamos a mandar un enlace sin tocar nada y nos dice que lo manda pero que lo tienen que aprobar. Vamos a probar ahora cambiando el valor del parámetro oculto a 0 con Firebug.

¡Funcionó!, el enlace ha pasado el filtro.

¿Cómo podemos aprovechar esto?, pués la forma más común es «XSS cross site scripting«. Veamos una prueba. Con el parámetro oculto otra vez en 0 mandamos el siguiente enlace y reto superado.

Links

Acabo de montar AperiSolve en una Raspi que tenía por casa pensando que sería coser y cantar, pero me he encontrado con que el repositorio no estaba preparado para todas las distros Linux de forma estándar. El resultado lo he colgado en Github, de modo que para montarlo en vuestra propia Raspi solo tenéis que seguir estos pasos:

1. Clonar el repositorio
git clone https://github.com/deurus/AperiSolve-Raspi3.git
cd AperiSolve-Raspi3/AperiSolve

2. Construir los contenedores
docker compose build
docker compose up -d

3. Abrir la web
http://<IP_RASPI>:5000

Si tenéis curiosidad de la adaptación que he tenido que hacer aquí están los pasos que he seguido:

1. Preparar el sistema
sudo apt update
sudo apt install -y git docker.io docker-compose
sudo usermod -aG docker $USER
newgrp docker

2. Clonar AperiSolve
git clone https://github.com/Zeecka/AperiSolve.git
cd AperiSolve

3. Crear la estructura de build para la imagen ARM/x86
nano docker-compose.yml

y pega este contenido:

FROM python:3.11-slim

RUN apt-get update && apt-get install -y \
    zip \
    p7zip-full \
    binwalk \
    foremost \
    exiftool \
    steghide \
    ruby \
    binutils \
    pngcheck \
    && rm -rf /var/lib/apt/lists/*

COPY aperisolve/ /aperisolve/

RUN pip install --no-cache-dir -r /aperisolve/requirements.txt

WORKDIR /aperisolve

CMD ["gunicorn", "-w", "4", "-b", "0.0.0.0:5000", "wsgi:app"]

4. Arreglar docker-compose.yml para ser válido y compatible

services:
  web:
    image: aperisolve-local
    build: .
    container_name: aperisolve-web
    ports:
      - "5000:5000"
    depends_on:
      - redis
      - postgres
    environment:
      DB_URI: "postgresql://aperiuser:aperipass@postgres:5432/aperisolve"

  worker:
    image: aperisolve-local
    container_name: aperisolve-worker
    depends_on:
      - redis
      - postgres
    environment:
      DB_URI: "postgresql://aperiuser:aperipass@postgres:5432/aperisolve"

  redis:
    image: redis:7
    container_name: aperisolve-redis

  postgres:
    image: postgres:16
    container_name: aperisolve-postgres
    environment:
      POSTGRES_USER: aperiuser
      POSTGRES_PASSWORD: aperipass
      POSTGRES_DB: aperisolve
    volumes:
      - postgres_data:/var/lib/postgresql/data

volumes:
  postgres_data:

5. Modificar aperisolve/config.py
nano config.py

y pega este contenido:

from pathlib import Path

IMAGE_EXTENSIONS = [".png", ".jpg", ".jpeg", ".gif", ".bmp", ".webp", ".tiff"]

WORKER_FILES = ["binwalk", "foremost", "steghide", "zsteg"]

RESULT_FOLDER = Path(__file__).parent.resolve() / "results"
RESULT_FOLDER.mkdir(parents=True, exist_ok=True)

6. Modificación de aperisolve/app.py

Sustituir la línea: app.config["SQLALCHEMY_DATABASE_URI"] = os.environ.get("DB_URI")
por:
default_db = "postgresql://aperiuser:aperipass@postgres:5432/aperisolve"
app.config["SQLALCHEMY_DATABASE_URI"] = os.environ.get("DB_URI", default_db)

7. Construir la imagen
docker build -t aperisolve-local .

8. Levantar los contenedores
docker compose down
docker compose up -d

9. Comprobar logs
docker logs aperisolve-web --tail=50
docker logs aperisolve-worker --tail=50

10. Acceder a la web
 - Desde cualquier máquina de la red local: http://IP-DE-LA-MAQUINA:5000
 - Desde la Raspi: http://localhost:5000

11. Limpieza (cuando necesites)
 - Reiniciar contenedores:
docker compose restart
 - Borrar resultados antiguos:
sudo rm -r aperisolve/results/*

Introducción

Este es un crackme hecho en .Net con dos Nags a parchear y un algoritmo muy sencillo pero que tendremos que parchear para poder resolverlo.

Las Nags

Se encuentran en los eventos de carga y cierre del formulario.

01-09-2014 07-30-07

// RegisterMe.Form1
private void Form1_Load(object sender, EventArgs e)
{
    Interaction.MsgBox("Register me pl0x!", MsgBoxStyle.OkOnly, "Nag!!!!");
}

// RegisterMe.Form1
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
    Interaction.MsgBox("Register me pl0x!", MsgBoxStyle.OkOnly, "Nag2!!!!");
}

 Para parchear un ejecutable realizado en .Net primero necesitamos ubicarnos. Abrimos IL Dasm y vamos al evento «Form_Load«, nos fijamos en los bytes y los buscamos con un editor hexadecimal. Fijaros bien en los bytes ya que siguen un orden específico, en la imágen del editor hexadecimal se aprecia perfectamente. Para que quede parcheada la Nag basta con sustituir los valores por ceros. Se parchea todo excepto el «RET (2A)».

01-09-2014 08-03-23

01-09-2014 08-04-01

Para la  otra Nag sería lo mismo.

El algoritmo

El algoritmo es muy sencillo, consiste en la concatenación de varias palabras y un número aleatorio. El problema viene con el número aleatorio ya que lo tendremos que parchear para poder registrar el programa.

// RegisterMe.Form1
private void Button1_Click(object sender, EventArgs e)
{
    this.shadow = this.rand.Next(1, 99999999);
    if (Operators.ConditionalCompareObjectEqual(this.TextBox2.Text, Operators.ConcatenateObject(this.TextBox1.Text + this.TextBox3.Text + this.TextBox4.Text + this.TextBox5.Text + this.TextBox6.Text + this.TextBox7.Text + this.TextBox8.Text + this.TextBox9.Text + this.TextBox1.Text, this.shadow), false))
    {
        this.Button2.Enabled = true;
        this.Button1.Enabled = false;
        this.Button1.Text = "Registered to Shadow";
        this.Text = "Registered to Shadow!";
    }
    else
    {
        Interaction.MsgBox("Incorrect serial, noob.", MsgBoxStyle.OkOnly, null);
    }
}

La concatenación quedaría así:

TextBox1.Text = Nuestro usuario + TextBox3.Text = «ur» + TextBox4.Text = «a» + TextBox5.Text = «stupid» + TextBox6.Text = «dumb» + TextBox7.Text = «idiotic» + TextBox8.Text = «crazy» + TextBox9.Text = «noob» + TextBox1.Text = Nuestro usuarioEl número aleatorio

 Ejemplo

  • Nombre: deurus
  • Clave: deurusurastupiddumbidioticcrazynoobdeurus98265385

Parcheando el número aleatorio

Buscamos el evento click en IL Dasm y nos fijamos que aparece el número «5F5E0FF» que en decimal equivale a «99999999«, buscamos los bytes en el editor hexadecimal y lo parcheamos a 1. De este modo anulamos la aletoriedad, ahora el número siempre es 1.

01-09-2014 09-25-23

01-09-2014 09-35-35

01-09-2014 09-36-59

Ahora ya podemos registrarnos.

01-09-2014 07-38-44

Links


Alerta de Spoiler: El reto está en activo a fecha de publicación. Spoiler alert: The challenge is still alive. Este
Introducción Este es un crackme de la web de Karpoff programado por Sotanez y realizado en Delphi. Como máximo nos
Introducción Tal y como nos adelanta el creador está programado en .NET. Lo abrimos para ver su comportamiento y a
http://youtu.be/b9-GdmIQINQ Lista de reproducción

Alerta de Spoiler: El reto está en activo a fecha de publicación.

Spoiler alert: The challenge is still alive.

Este tipo de retos son de lo más variopinto pero una de las primeras cosas que se suele hacer es ver el código fuente y fijarse en los enlaces para hacernos una idea del tipo de vulnerabilidades a explotar. Empezamos por explorar el código fuente.

<html>
<head>
    <link href="../../assets/css/bootstrap.min.css" rel="stylesheet" type="text/css">
    <script src="../../assets/js/jquery.min.js" type="text/javascript"></script>
    <meta charset="UTF-8">
    <style>
        body{
            background-color: #111;
        }
        .main{
            background-color: #fff;
        }
    </style>
</head>
<body>
<div class="container main">
    <div class="jumbotron">
        <div class="container">
            <h1>ジェフのショップ</h1>
            <p>ジェフのショップへようこそ、私たちは...私たちは、新しいセキュリティシステムを幸せ持っています <img height="100" width="100" src="source/cat.gif"></p>
            <p><a class="btn btn-primary btn-lg" href="#" role="button">もっと詳しく知る »</a></p>
        </div>
    </div>
    <div class="row">
        <!-- Example row of columns -->
        <div class="row text-center">
            <div class="col-md-4">
                <h2>車</h2>
                <p class="text-center" style="margin: 20px;">我々 50,000円の価格で車を販売しています. </p>
                <p><a class="btn btn-danger " href="#" role="button">今すぐ購入<span class="glyphicon glyphicon-shopping-cart"></span></a></p>
            </div>
            <div class="col-md-4">
                <h2>剣</h2>
                <p class="text-justify" style="margin: 20px;">我々は、 25円の価格のために地球全体の最も鋭い剣を販売しています </p>
                <p><a class="btn btn-danger " href="#" role="button">今すぐ購入<span class="glyphicon glyphicon-shopping-cart"></span></a></p>
            </div>
            <div class="col-md-4">
                <h2>赤ジェフの毒</h2>
                <p class="text-justify" style="margin: 20px;">我々は毒、世界に存在するほとんどの不治の毒を販売しています。プライスレス90000.</p>
                <p><a class="btn btn-danger " href="#" role="button">今すぐ購入<span class="glyphicon glyphicon-shopping-cart"></span></a></p>
            </div>
        </div>
        <hr>
    </div>
    <div class="row">
        <!-- Example row of columns -->
        <div class="row text-center">
            <div class="col-md-4">
                <h2>魔法の脳</h2>
                <p class="text-justify" style="margin: 20px;">彼らは私たちの脳販売しているいくつかの場面で非常に便利です。その価格は約10円です.</p>
                <p><a class="btn btn-danger " href="#" role="button">今すぐ購入<span class="glyphicon glyphicon-shopping-cart"></span></a></p>
            </div>
            <div class="col-md-4">
                <h2>侵入テスト</h2>
                <p class="text-justify" style="margin: 20px;">私たちはあなたのウェブページやサーバーで完全なセキュリティを提供します。これはジェフの店の最高の製品です。</p>
                <p><a class="btn btn-danger " href="#" role="button">今すぐ購入<span class="glyphicon glyphicon-shopping-cart"></span></a></p>
            </div>
        </div>
        <hr>
    </div>
    <footer>
        <p>© ジェフは2015フンメルス</p>
    </footer>
</div>
</body>
</html>

A simple vista no hay nada sospechoso pero me llama la atención el enlace de la imagen del gatito «source/cat.gif«. Si fisgamos dentro de la carpeta «source» podemos ver que nos muestra el contenido de la carpeta como se puede apreciar en la imagen a continuación.

Contenido de la carpeta source

Contenido de la carpeta source

La carpeta «app» suena interesante. Hacemos clic y vemos lo siguiente.

Notice: Undefined index: commit in C:/xampp/htdocs/challenge-land/Realistic/shop/source/app/index.php on line 2

Vemos que el error mostrado muestra más información de la debida y la aprovecharemos en beneficio propio. Aquí la clave está en el fichero index.php y en el parámetro commit. Haremos una prueba para ver que vamos por el buen camino.

http://challengeland.co/Realistic/e4633b53f9/source/app/index.php?commit

y recibimos el error «The commit number not found.»

Probamos entonces añadiendo números al parámetro commit y nos fijamos en las respuestas.

http://challengeland.co/Realistic/e4633b53f9/source/app/index.php?commit=1
すべて更新
http://challengeland.co/Realistic/e4633b53f9/source/app/index.php?commit=2
Jeff@shop.com 2013年5月5日 - >ちょっと私たちは.htpasswdの使用する必要がジェームズと.htaccess保護...本当に安全です。すべてのファイルを更新します
http://challengeland.co/Realistic/e4633b53f9/source/app/index.php?commit=3
すべて更新
http://challengeland.co/Realistic/e4633b53f9/source/app/index.php?commit=4
すべて更新
http://challengeland.co/Realistic/e4633b53f9/source/app/index.php?commit=5
すべて更新
http://challengeland.co/Realistic/e4633b53f9/source/app/index.php?commit=6
James@shop.com 2013年5月7日に - >ジェフ、大丈夫、私はそれに仕事に行きます。すべてのファイルを更新し、覚えています - jeffshop:adm1n$2015*+
http://challengeland.co/Realistic/e4633b53f9/source/app/index.php?commit=7
すべて更新
http://challengeland.co/Realistic/e4633b53f9/source/app/index.php?commit=8
jeff@shop.com 2013年5月9日 - >ジェームズ、良い仕事...新しいユーザーとパスがあります jeffcrazyshop:h4rDtoF1nD

Hay varias respuestas sugerentes pero quizá la más relevante es la 8. Ahora bien, solo falta encontrar donde introducir el usuario y la clave.

Si volvemos a la página principal vemos en el enlace algo interesante, me refiero a index.php?page=index. Tras probar varias cosas la que funciona es la típica, admin.

http://challengeland.co/Realistic/e4633b53f9/index.php?page=admin

Al entrar vemos que nos redirige al index de nuevo tras pocos segundos. Aquí hay dos opciones, desactivar javascript para evitar la redirección o entrar directamente a la página admin.php. Optamos por el camino fácil entrando directamente en admin.php:

http://challengeland.co/Realistic/e4633b53f9/admin.php

Login

Login

Introduciendo los datos obtenidos anteriormente nos muestra la querida flag.

Enlaces

Introducción

Este es un crackme de la web de Karpoff programado por Sotanez y realizado en Delphi. Como máximo nos deja meter nombres de 10 dígitos.

El algoritmo

Es un algoritmo muy sencillo pero veremos que nos tendremos que fijar en el DUMP de Olly para saber que demonios hace. Como de costumbre abrimos Olly y en las «Referenced Strings» localizamos la palabra «Registrado«, pinchamos en ella y localizamos la porción de código que nos interesa. Vamos a analizarla.

bucles

Vemos 3 bucles, el primero pone la memoria (Dump) a cero, el segundo guarda nuestro nombre (errata en la imagen) en el Dump y el tercero realiza la suma de los valores ascii del nombre. Hasta aquí todo bien, pero vamos a hacer una prueba para el nombre deurus.

  • Nombre: deurus
  • Serial: 64+65+75+72+75+73 = 298 (664 en decimal)

Probamos el serial en el programa y nos da error, vale, vamos a analizar más a fondo los bucles.

El primer bucle hemos dicho que pone la memoria a 0, en concreto desde «45BC60» y de 4 en 4 (fíjate en el Add 4), es decir, pone a 0 los offsets 45BC60, 45BC64, 45BC68, 45BC6C, 45BC70, 45BC74, 45BC78, 45BC7C, 45BC80, 45BC84, ya que el bucle se repite 10 veces. En la imágen queda claro.

 pasado1bucle2

El segundo bucle se repite 11 veces y lo que hace es guardar en el dump el valor ascii de las letras de nuestro nombre. En la imagen lo vemos.

pasado2bucle

A primera vista ya vemos un valor extraño en la posición 45BC80, y es que cuando debiera haber un 0, hay un 12. Vamos a ver como afecta esto al serial final.

El tercer bucle se repite 10 veces y lo que hace es sumar los valores que haya en el DUMP en las posiciones anteriormente citadas.

pasado3bucle

En concreto suma 64+65+75+72+75+73+0+0+12+0 = 2AA (682 en decimal). Probamos 682 como serial y funciona. Realizando más pruebas vemos que para nombres con un tamaño inferior a 5 letras se ocupan las posiciones 45BC70 y 45BC80 con valores extraños, el resto de posiciones se mantienen a 0. En las imágenes inferiores se pueden apreciar más claramente los valores extraños.

Nombre de tamaño < 5.

dump1letra

Nombre de tamaño >5 y <9

05-09-2014 00-06-19

Nombre de tamaño = 10

 04-09-2014 16-37-31

En resumen:

Nombre de tamaño < 5 –> Ascii SUM + 14h
Nombre de tamaño >5 y <9 –> Ascii SUM + 12h
Nombre de tamaño =10 –> Ascii SUM

Con esto ya tenemos todo lo que necesitamos para nuestro keygen.

char Nombre[11];
GetWindowText(hwndEdit1, Nombre, 11);
char Serial[20];
int len = strlen(Nombre);
int suma = 0;
for(int i = 0; i <= len; i = i + 1)
{
   suma += Nombre[i];
}
if(len < 5){
   suma +=0x14;
}
if(len > 5 && len < 9){
   suma +=0x12;
}
wsprintf(Serial,"%d",suma);
SetWindowText(hwndEdit2, TEXT(Serial));

Links


Los retos criptográficos son muy variados y muchas veces la dificultad está en saber a que te enfrentas. En este
El reto Se nos proporciona la imagen anterior y se nos invita a resolver la ecuación para el menor entero
Warning: This challenge is still active and therefore should not be resolved using this information. Aviso: Este reto sigue en
Introducción Javascript 1 (Serial a la vista) Javascript 2 (La función charAt()) Javascript 3 (Input) Javascript 4 (Fuerza bruta manual) Javascript

Los retos criptográficos son muy variados y muchas veces la dificultad está en saber a que te enfrentas. En este caso pasa eso, te dan un código y si no has visto algo parecido en la vida, no sabes por donde empezar. El título del autor da una pequeña pista pero para los desconocedores no es suficiente. La pista es el título y dice «WTF?!?» y el código a descifrar es el siguiente:

[-]>[-]<
>+++++++++++[<+++++++++++>-]<.
>+++[<--->-]<-.
>++[<++>-]<++.
+.
>++++[<---->-]<-.
---.
+++.
.
>+++[<+++>-]<.
>+++[<--->-]<+.
>++++[<++++>-]<-.
>++++[<---->-]<--.
>+++[<+++>-]<-.
>++[<-->-]<--.
-.

Si eres una persona con recursos, realizaras varias búsquedas por la red y al final llegarás a la conclusión de que te enfrentas a BRAINFUCK, un lenguaje de programación esotérico como ya vimos en el reto de Root-Me.

Enlaces

El reto

Se nos proporciona la imagen anterior y se nos invita a resolver la ecuación para el menor entero positivo que representa cada fruta. La solución del reto es concatenar «Flag-» a la suma de los valores de las tres frutas.

Análisis inicial

El enunciado es breve pero ya nos adelanta que existen varias soluciones y que además sólo quieren los números más pequeños que podamos encontrar.

Las frutas están muy bien y son muy sanas pero a nosotros se nos hace más sencillo plantear la ecuación con letras.

\begin{align}
&  \frac{x}{y+z}+\frac{y}{x+z}+\frac{z}{x+y}=4\\
\end{align}

Para arrojar algo de luz veamos la representación gráfica en 2D y 3D con la ayuda de Desmos.

3D

Las gráficas más que luz nos traen oscuridad de modo que preguntemos a ChatGPT.

ChatGPT

resuelve: (x/y+z)+(y/x+z)+(z/x+y)=4 para enteros positivos

Dado que las variables x, y, z son enteros positivos, podemos intentar encontrar una solución para la ecuación bajo estas condiciones. Sin embargo, encontrar una solución exacta puede ser complejo debido a la naturaleza no lineal de la ecuación. Aun así, podemos intentar algunos enfoques:

  • Prueba y error: Podemos probar diferentes combinaciones de valores enteros positivos para x, y, z y ver si satisfacen la ecuación.
  • Análisis de casos específicos: Podemos comenzar analizando casos más simples, como cuando dos de las variables son iguales, y luego ampliar nuestra búsqueda desde allí.
  • Análisis gráfico o numérico: Utilizando herramientas gráficas o numéricas, podríamos identificar posibles soluciones y luego verificar si son enteros positivos.

Voy a realizar un análisis numérico con un rango limitado de valores para ver si encontramos alguna solución que cumpla con las condiciones. Vamos a probar con valores de 1 a 10 para cada variable.

El análisis numérico para valores de en el rango de 1 a 10 no ha encontrado ninguna solución que satisfaga la ecuación. Esto sugiere que, dentro de este rango, no existen combinaciones de enteros positivos que cumplan con la ecuación.

Dado que la ecuación es bastante compleja y no lineal, es posible que las soluciones, si existen, se encuentren fuera del rango considerado o que requieran un enfoque diferente para ser identificadas. Si tienes un rango específico de valores en mente o si hay alguna otra restricción o contexto relevante, por favor házmelo saber para poder ajustar el análisis en consecuencia.

Básicamente nos está invitando a utilizar prueba y error para encontrar una solución, y el prueba y error de las matemáticas no es más que la fuerza bruta en programación.

El código

Partiendo del problema anterior dame un código en python que realice una comprobación recursiva de todas las variables con un rango de 1 a 999.

soluciones = []
rango_valores_x = range(1, 999)
rango_valores_y = range(1, 999)
rango_valores_z = range(1, 999)

for x in rango_valores_x:
    for y in rango_valores_y:
        for z in rango_valores_z:
            # Calculamos el valor de la expresión para cada combinación de x, y, z
            valor = x / (y + z) + y / (x + z) + z / (x + y)
            # Comprobamos si el valor es igual a 4 y agregamos la solución a la lista
            if abs(valor - 4) < 1e-6:  # Usamos una pequeña tolerancia para evitar errores de precisión
                soluciones.append((x, y, z))

print(soluciones)

Dejo resaltada la línea 12 del código ya que en ella reside el problema. Está comprobando con un margen de tolerancia de 10-6 ya que el resultado de las diferentes fracciones no da como resultado exacto 4. Esto es un problema ya que nosotros necesitamos que de exactamente 4 para validar los valores enteros de x, y y z. Pongo un ejemplo para el que se haya perdido con una solución válida para la tolerancia 10-6 siendo x=2, y=264 y z=993.

\begin{align}
&  \frac{2}{264+993}+\frac{264}{2+993}+\frac{993}{2+264}=4.000000429\\
\end{align}

En otras palabras, ChatGPT nos ha brindado una solución aproximada que no sirve para nuestro propósito. Seguimos probando con el código anterior quitando la tolerancia y con rangos mayores hasta que en 106 paro. Me acaba de quedar claro que con la fuerza bruta no vamos a ninguna parte, o más bien, no tenemos capacidad de computación para resolverlo de ésta manera.

¿Qué está pasando?

Lo que pasa es que estamos ante una ecuación algebraica de 3 incógnitas que deben ser enteros positivos cuya solución se alcanza mediante la teoría de curvas elípticas.

Curvas elípticas

Las curvas elípticas son fundamentales en matemáticas avanzadas, representadas por la ecuación y2=x3+Ax+B, donde A y B son constantes. Estas curvas son un punto de encuentro entre la geometría, la teoría de números y el álgebra, ofreciendo un campo rico para la exploración y el análisis. En este CTF, nos enfocaremos en los puntos racionales de las curvas elípticas. Utilizando el método tangente-secante, un procedimiento geométrico iterativo, buscaremos ampliar un conjunto finito de soluciones conocidas a la ecuación de la curva. Este método nos permite indagar en la estructura de las soluciones racionales, que potencialmente pueden ser infinitas. Además, estableceremos una conexión entre las soluciones enteras de las ecuaciones diofánticas y los puntos racionales en las curvas elípticas partiendo de la ecuación (1) especificada en el análisis inicial. A pesar de su aparente simplicidad, esta ecuación es conocida por presentar soluciones mínimas de gran tamaño.

Adecuación

Antes de nada, necesitamos saber el grado de la ecuación, de modo que planteamos la ecuación en forma polinómica estándar deshaciéndonos de los denominadores.

\begin{align}
\begin{split}
n(a+b)(b+c)(c+a)=a(a+b)(c+a)+b(b+c)(a+b)+c(c+a)(b+c)
\end{split}
\end{align}

Ahora necesitamos expandir y simplificar para llegar a la conclusión de que estamos ante una ecuación diofántica de grado 3. Este proceso es engorroso por la cantidad de términos a manejar así que vamos a utilizar Mathematica como software de respaldo para finalmente obtener el polinomio en la forma de Weierstrass según la ecuación 4.

\begin{align}
&  y^2=x^3+109x^2+224x\\
\end{align}

donde:

\begin{align}
x = \frac{−28(a+b+2c)}{(6a+6b−c)}\\
y = \frac{364(a−b)}{(6a+6b−c)}
\end{align}

Las relación entre la ecuación 3 y los puntos de la curva elíptica se establecen mediante la ecuación 4. Las transformaciones entre las soluciones (a, b, c) y los puntos (x, y) en la curva elíptica vienen dados por las ecuaciones 5 y 6. Con estas transformaciones, cada solución de la ecuación diofántica se puede representar como un punto en la curva elíptica, y las operaciones de suma de puntos en la curva elíptica pueden usarse para encontrar nuevas soluciones de la ecuación diofántica.

Mathematica

El código que tenéis a continuación pertenece al gran trabajo de Aditi Kulkarni [7], que además nos da el resultado para cualquier valor de n. Ojo porque para n=4 el resultado tiene 81 dígitos, para n=6 tiene 134, para n=10 tiene 190 y para n=12 asciende a 2707 dígitos.

(* Asignar un valor numérico a n *)
n = 4;
(* Definir la ecuación de una curva elíptica en términos de n *)
curve4 = y^2 == x^3 + (4*n^2 + 12*n - 3)*x^2 + 32*(n + 3)*x;
(* Encontrar un punto racional en la curva que no sea (4,0) *)
P4 = {x, y} /. First[FindInstance[curve4 && x != 4 && y != 0, {x, y}, Integers]];
(* Función para calcular la pendiente entre dos puntos en la curva, 
   o la derivada en el punto si son iguales *)
Slope4[{x1_, y1_}, {x2_, y2_}] := 
  If[x1 == x2 && y1 == y2, 
     ImplicitD[curve4, y, x] /. {x -> x1, y -> y1}, 
     (y2 - y1)/(x2 - x1)];
(* Función para calcular la intersección en y de la línea entre dos puntos 
   o la tangente en el punto si son iguales *)
Intercept4[{x1_, y1_}, {x2_, y2_}] := y1 - Slope4[{x1, y1}, {x2, y2}]*x1; 
(* Función para encontrar el siguiente punto racional en la curva *)
nextRational4[{x1_, y1_}, {x2_, y2_}] := 
  {Slope4[{x1, y1}, {x2, y2}]^2 - CoefficientList[curve4[[2]], x][[3]] - x1 - x2, 
   -Slope4[{x1, y1}, {x2, y2}]^3 + Slope4[{x1, y1}, {x2, y2}]*(CoefficientList[curve4[[2]], x][[3]] + x1 + x2) - Intercept4[{x1, y1}, {x2, y2}]};
(* Función para convertir un punto en la curva elíptica a una solución diofántica *)
ellipticToDiophantine[n_, {x_, y_}] := 
  {(8*(n + 3) - x + y)/(2*(4 - x)*(n + 3)), 
   (8*(n + 3) - x - y)/(2*(4 - x)*(n + 3)), 
   (-4*(n + 3) - (n + 2)*x)/((4 - x)*(n + 3))};
(* Usar nextRational4 para iterar desde P4 hasta encontrar una solución 
   válida y positiva para la ecuación diofántica *)
sol4 = ellipticToDiophantine[n, 
   NestWhile[nextRational4[#, P4] &, P4, 
     ! AllTrue[ellipticToDiophantine[n, #], Function[item, item > 0]] &]];
(* Escalar la solución para obtener enteros mínimos *)
MinSol4 = sol4*(LCM @@ Denominator[sol4])
(* Suma de las tres variables*)
Total[MinSol4]

Solución

Concatenando Flag- con el resultado de Mathematica tenemos la ansiada flag.

Flag-195725546580804863527010379187516702463973843196699016314931210363268850137105614

Conclusiones

ChatGPT ha demostrado ser eficaz en el análisis y la resolución de problemas, siempre que se le proporcione el contexto adecuado. Sin embargo, es importante ser conscientes de que la respuesta proporcionada puede ser aproximada, especialmente si la solución requiere una gran cantidad de recursos computacionales. Por ejemplo, al trabajar con una ecuación diofántica y valores específicos para (x) e (y), ChatGPT puede ayudar a calcular puntos como (P), (2P), (3P), etc., pero hay que tener en cuenta que los resultados para estos puntos pueden ser estimaciones.

Finalmente, os invito a leer la solución de Mingliang Z. [4], en la que se resuelve el problema por completo y de forma muy detallada.

Enlaces

Warning: This challenge is still active and therefore should not be resolved using this information.
Aviso: Este reto sigue en activo y por lo tanto no se debería resolver utilizando esta información.

Table of Contents

Intro

This crackme is for the challenge Mobile 2 of canyouhack.it.
This time you need to understand how the crackme works over the web.

Decompiling

The crackme is given again at Google Play, so the first step is to install and recover the APK for decompiling. The latter, I leave to you.
Open the victim with APK Studio and view the content of Mobile2.java
First we view one link:
http://canyouhack.it/Content/Challenges/Mobile/2/index.php
 If we go to the link, we view one string like a hash: 68a571bcf7bc9f76d43bf931f413ab2c. Umm, it’s like MD5. Go to decrypt online and we get the pass: «canyouhack.it». But if we test this password in the crackme, surprise!, nothing happens. We need to continue analyzing the code. Later we view the next interesting link:
«http://canyouhack.it/Content/Challenges/Mobile/2/submit.php?Token=» + Mobile2.token + «&Attempts=»
The program submit one token and concatenate with the number of attempts. Ok but what is the token and what is the number of attempts?
In this point we have to try with the information we already have.
Testing with the link of bottom we get “Nice try!” message.
http://canyouhack.it/Content/Challenges/Mobile/2/submit.php?Token=68a571bcf7bc9f76d43bf931f413ab2c&&Attempts=0
Testing with the link of bottom we get “Very Good, the password is Top*****!” message.
http://canyouhack.it/Content/Challenges/Mobile/2/submit.php?Token=68a571bcf7bc9f76d43bf931f413ab2c&&Attempts=1

  Links