HackIt 2024 / EE32 / Level 2

El level 2 sigue estando entre los clasificados como muy fáciles.

https://ikasten.io/ee32/hackit/level2/level2.html

Igual que en el level anterior, analizamos qué operaciones se llevan a cabo para comprobar que el password introducido es correcto (al final se compara con un string concreto: umcjqhmdohdzchm)

$(document).ready(function(){$("#password").keyup(function(o){
r=$("#password").val();function num(s){x=s+'';y=x.charCodeAt(0);if(0xD800<=y&&y<=0xDBFF){q = y;if(x.length === 1){return y;}z=x.charCodeAt(1);return ((q - 0xD800)*0x400)+(z - 0xDC00)+0x10000;}if(0xDC00<=y&&y<=0xDFFF){return y;}return y;}
d="txhupnqbgvzyjvfbadnzkmytwdauwpeeojiowkzrmrnxlxcsskbjtrifhlomldsivceyqggphcfqua";c=0;o="";for(var i=0;i<r.length;i++){c=(num(r.charAt(i))+c)%78;o+=d.charAt(c);}
$("#password").css({"background-color":o == "umcjqhmdohdzchm"?"#8f8":"#f88"});
});});

y revertimos el proceso:

def num(s):
    x = s + ''
    y = ord(x[0])
    if 0xD800 <= y <= 0xDBFF:
        q = y
        if len(x) == 1:
            return y
        z = ord(x[1])
        return ((q - 0xD800) * 0x400) + (z - 0xDC00) + 0x10000
    if 0xDC00 <= y <= 0xDFFF:
        return y
    return y

d = "txhupnqbgvzyjvfbadnzkmytwdauwpeeojiowkzrmrnxlxcsskbjtrifhlomldsivceyqggphcfqua"
target = "umcjqhmdohdzchm"
c = 0

password = []

for char in target:
    target_index = d.index(char)
    for potential_char in range(32, 127):  # ASCII printable range
        temp_c = (num(chr(potential_char)) + c) % 78
        if temp_c == target_index:
            password.append(chr(potential_char))
            c = temp_c
            break

password = ''.join(password)
print("The password is:", password)

Curiosamente, aquí pedimos que se revisara la prueba, porque obteníamos claves válidas (esta prueba mostraba el input text de la página en verde cuando introducías una clave que pasaba las validaciones correctamente) que el servidor no aceptaba al enviarla. Desde la org nos atendieron enseguida y modificaron el level para que diera por buena cualquier clave que pasara correctamente las validaciones.

HackIt 2024 / EE32 / Level 1

Briefing del HackIt/SolveIt 2024

Un año más (y van unos cuantos, desde la Euskal VII) hemos vuelto a participar en el HackIt. Este año venía con novedades importantes: Marcan cedía el testigo a OntzA (Xabier Eizmendi, a la izquierda de la foto) de NavarParty, que junto a Imobilis (Juan Traverso, derecha), han organizado una excelente edición.

Había más retos y más diversidad en las pruebas, desde los muy fáciles a alguno muy complicado (sólo superado por w0pr, as usual 🙂

Al lío. Esta vez me encargué de hacer una copia de los retos, tanto del hackit como del solveit. Están publicados en Ikasten.io, siguiendo este esquema de URL:

HackIt:

https://ikasten.io/ee32/hackit/level1/level1.html

SolveIt:

https://ikasten.io/ee32/solveit/level1/level1.html

El primer level del HackIt, como suele ser habitual ha sido muy sencillo. No siempre es así, por ejemplo, creo que fue el año pasado, en una prueba de WebGL, fue una excepción.

En el código fuente vemos una simple operación de XOR

$(document).ready(function(){$("#password").
keyup(function(o){<br>r=$("#password").val();t="youknowit";c=[0x3c,0xe,0x6,0x12,0x1e,0x5c,0x16,0x1a,0xd];
e="";for(i=0;i<r.length;i++){
e+=String.fromCharCode(r.charCodeAt(i)^c[i%9]);}<br>$("#password").css({"background-color":e==t?
"#8f8":"#f88"});<br>});});

Reversible muy fácilmente:

def reverse_algorithm(encrypted_str, c):<br> password = ""<br> for i in range(len(encrypted_str)):<br> char = chr(ord(encrypted_str[i]) ^ c[i % len(c)])<br> password += char<br> return password<br><br>encrypted_str = "youknowit"<br>c = [0x3c, 0x0e, 0x06, 0x12, 0x1e, 0x5c, 0x16, 0x1a, 0x0d]<br><br>password = reverse_algorithm(encrypted_str, c)<br>print("The password is:", password)

Easy peasy!

OpenWebUI and WebSearch

OpenWebUI allows you to search using some search providers, like searxng, google_pse, brave, serpstack and serper. You just need to open Workspace/Documents/Web Params. Then, select a web search engine:

Add the API Key for your provider:

Now, whenever you want to search something online and inject the answer as context for your next prompts, enable Web Search in the prompt field:

And send your message. For instance:

List of the candidacies that are running in the European elections

(«Nombre de las candidaturas que se presentan a elecciones europeas»)

OpenWebUI-LiteLLM integration

LiteLLM is a package that simplifies API calls to various LLM (Large Language Model) providers, such as Azure, Anthropic, OpenAI, Cohere, and Replicate, allowing calls to be made in a consistent format similar to the OpenAI API. Integrated with OpenWebUI, it allows this user interface to work with any LLM provider. In my case, I use OpenWebUI+LiteLLM to query groq/llama3-70b, Anthropic Claude Opus 3, GPT-4o, and Gemini-1.5-pro, among others.

The problem is that the 0.2.0 release of OpenWebUI stopped integrating a version of LiteLLM. That doesn’t mean it can’t be used; rather, LiteLLM needs to be launched separately, through a Docker container, for example.

Let’s launch LiteLLM:

$ docker run -d --name litellm -v $(pwd)/config.yaml:/app/config.yaml -p 4000:4000 -e LITELLM_MASTER_KEY=sk-12345 ghcr.io/berriai/litellm:main-latest --config /app/config.yaml --detailed_debug

That command launches LiteLLM listening on port 4000, using config.yaml as the configuration file. The config.yaml file might look something like this (don’t forget to input your API Keys):

general_settings: {}
litellm_settings: {}
model_list:
  - model_name: claude-3-opus-20240229 # user-facing model alias
    litellm_params:
      api_base: https://api.anthropic.com/v1/messages
      api_key: sk-
      model: claude-3-opus-20240229
  - model_name: gpt-4-turbo 
    litellm_params: 
      api_base: https://api.openai.com/v1
      api_key: sk-
      model: gpt-4-turbo
  - model_name: gpt-4-vision-preview 
    litellm_params: 
      api_base: https://api.openai.com/v1
      api_key: sk-
      model: gpt-4-vision-preview
  - model_name: gpt-4o 
    litellm_params: 
      api_base: https://api.openai.com/v1
      api_key: sk-
      model: gpt-4o-2024-05-13
  - model_name: gpt-3.5-turbo 
    litellm_params: 
      api_base: https://api.openai.com/v1
      api_key: sk-
      model: gpt-3.5-turbo
  - model_name: gemini-1.5-pro
    litellm_params:
      api_key: AI-
      model: gemini/gemini-1.5-pro
  - model_name: groq/llama3-70b-8192
    litellm_params:
      api_key: gsk_
      model: groq/llama3-70b-8192
router_settings: {}

Now, from OpenWebUI, go to Settings/Connections and enter http://host.docker.internal:4000/v1 in the host field and sk-12345 (or the key you set for LiteLLM when you launched it via Docker) in the API-Key field.

OpenWebUI: integración con LiteLLM

LiteLLM es un paquete que simplifica las llamadas a API de varios proveedores de LLM (Large Language Model), como Azure, Anthropic, OpenAI, Cohere y Replicate, permitiendo realizar llamadas en un formato consistente similar al de la API de OpenAI. Integrado con OpenWebUI permite usar este interfaz de usuario contra cualquier proveedor LLM. En mi caso, uso OpenWebUI+LiteLLM para hacer consultas a groq/llama3-70b, Anthropic Claude Opus 3, GPT-4o y Gemini-1.5-pro, entre otros.

El problema es que la release 0.2.0 de OpenWebUI dejó de integrar una versión de LiteLLM. Eso no quiere decir que no se pueda usar, sino que hay que lanzar LiteLLM aparte, a través de un container Docker, por ejemplo.

Lanzamos LiteLLM:

$ docker run -d --name litellm -v $(pwd)/config.yaml:/app/config.yaml -p 4000:4000 -e LITELLM_MASTER_KEY=sk-12345 ghcr.io/berriai/litellm:main-latest --config /app/config.yaml --detailed_debug

Esa orden lanza LiteLLM a la escucha en el puerto 4000, usando config.yaml como fichero de configuración. El fichero config.yaml puede ser algo como este (no te olvides de introducir tus API Keys):

general_settings: {}
litellm_settings: {}
model_list:
  - model_name: claude-3-opus-20240229
    litellm_params:
      api_base: https://api.anthropic.com/v1/messages
      api_key: sk-
      model: claude-3-opus-20240229

  - model_name: gpt-4-turbo # user-facing model alias
    litellm_params: 
      api_base: https://api.openai.com/v1
      api_key: sk-
      model: gpt-4-turbo

  - model_name: gpt-4-vision-preview 
    litellm_params: 
      api_base: https://api.openai.com/v1
      api_key: sk-
      model: gpt-4-vision-preview

  - model_name: gpt-4o 
    litellm_params: 
      api_base: https://api.openai.com/v1
      api_key: sk-
      model: gpt-4o-2024-05-13

  - model_name: gpt-3.5-turbo 
    litellm_params: 
      api_base: https://api.openai.com/v1
      api_key: sk-
      model: gpt-3.5-turbo

  - model_name: gemini-1.5-pro
    litellm_params:
      api_key: AI-
      model: gemini/gemini-1.5-pro

  - model_name: groq/llama3-70b-8192
    litellm_params:
      api_key: gsk_
      model: groq/llama3-70b-8192

router_settings: {}

Ahora, desde OpenWebUI, entramos en Settings/Connections e introducimos http://host.docker.internal:4000/v1 en el campo host y sk-12345 (o la clave que hayas puesto a LiteLLM cuando lo lanzaste vía docker) en el API-Key.