Cómo usamos /goal para encontrar errores en Patch the Planet
CYBERSECURITY ANÁLISIS DESTACADO

Cómo usamos /goal para encontrar errores en Patch the Planet

FUENTE

The Trail of Bits Blog

DATE

READ

10 min de lectura

El artículo explica cómo la función de /goal de Codex, un aviso basado en objetivos que permite al modelo perseguir criterios de éxito autodefinidos, mejora la búsqueda de errores para Patch the Planet. Los equipos la …

La característica /goal de Codex amplifica la búsqueda de errores, pero obtener buenos resultados requiere el aviso correcto, el alcance adecuado y el número correcto de resultados por ejecución. Para Patch the Planet, nuestra iniciativa conjunta con OpenAI para encontrar y corregir errores en software de código abierto, dirigimos Codex hacia algunos de los repositorios de código más utilizados y auditados del mundo, como Rust, curl y zlib. Una herramienta apareció una y otra vez en nuestros canales internos de informes de errores: /goal, que le otorga a Codex un objetivo abierto y le permite trabajar de manera independiente hacia una condición de éxito. Aquí hay algunos aspectos destacados: /goal encontró cada error de Rust que enviamos, incluyendo un agujero de solidez y una mala compilación que ahora se ha corregido en Rust 1.98, a partir de un solo pipeline de análisis de variantes. Transformó los CVE anteriores de cada proyecto en reglas de Semgrep que debían activarse en la versión vulnerable y permanecer en silencio en la corregida, y luego marcó 11 coincidencias de variantes en múltiples proyectos. Descubrió dos posibles errores de escalada de privilegios de alta severidad en el componente SAML de Keycloak durante un análisis inicial. Durante las primeras semanas de Patch the Planet, nuestros ingenieros convergieron independientemente en tres técnicas para utilizar /goal. Descubrimos que sacar el máximo provecho de /goal significa tratar el aviso como un conjunto de criterios específicos de éxito, no como un conjunto de instrucciones. (Cabe mencionar que esta publicación de blog utiliza /goal para referirse a un aviso basado en objetivos en general. Codex también puede establecer objetivos para sí mismo a través de una llamada de herramienta, y así es como recomendamos que todos lo utilicen; rara vez escribimos el comando de barra nosotros mismos.) 1. Deja que Codex escriba el objetivo El arte de utilizar /goal es el diseño del aviso, y descubrimos que Codex se conoce mejor a sí mismo. Internamente, nuestro consejo más repetido sobre /goal fue utilizar Codex para ayudar a redactar cada aviso de /goal. Le proporcionamos a Codex archivos de modelo de amenaza y el contexto sobre lo que estamos buscando, y luego le decimos que escriba el aviso del objetivo. Como se mencionó antes, /goal es una herramienta que Codex puede invocar a sí mismo, y algunos ingenieros dejaron de escribir objetivos a mano por completo. $goal-prompt basado en el modelo de amenaza escribir objetivo para encontrar un único problema crítico (RCE) explotable por un atacante remoto para kubernetes-client. El kubernetes-client se usa en configuración normal, los usuarios remotos maliciosos explotan. Figura 1: Un meta-aviso de uno de nuestros ingenieros pidiendo a Codex que cree un aviso de objetivo. Los resultados se muestran en la figura 2. Esto funciona porque Codex conoce mejor el objetivo y sus propias tendencias que lo que podemos especificar de antemano. Puede traducir un modelo de amenaza en criterios de éxito concretos y verificables, nombrar las rutas de código que valga la pena priorizar y formular el resultado con suficiente precisión para que una ejecución realmente converja. Un objetivo escrito de esta manera tiende a ser más ajustado que uno que escribiríamos a ciegas, y toma una fracción del tiempo. Dejar que el modelo redacte el objetivo también cierra una brecha que de otro modo perderíamos. Cualquier resultado que definas puede satisfacerse de maneras que no pretendías, y el modelo suele ser el primero en detectar dónde están las fáciles salidas. Ahora, cuando pedimos a Codex que redacte un objetivo, le pedimos que evalúe su propio objetivo identificando las formas en que un modelo futuro podría ser perezoso en su enfoque y que revise los criterios para eliminarlas antes de que comience la ejecución. También construimos herramientas que facilitan a Codex verificar su propio trabajo. Por ejemplo, notamos que Codex tiene una tendencia a saltarse la lectura de todo el código fuente incluso cuando se le pide explícitamente. Construimos aicov, una herramienta que rastrea qué líneas de código ha leído realmente Codex, para que no pueda “hacer trampa”. Este es un proceso iterativo. A medida que encontramos más atajos que toma un modelo, los excluimos de la siguiente versión del aviso. 2. Define el resultado, no el camino Un buen objetivo nombra el resultado, lo define con precisión y luego impone persistencia: /goal Auditar el repositorio kubernetes-client en este espacio de trabajo para encontrar exactamente una vulnerabilidad crítica de ejecución remota de código previamente no reportada, alcanzable en configuración normal/predeterminada del cliente por un usuario o servidor remoto malicioso que controle únicamente las respuestas de red/API, objetos de Kubernetes que el cliente obtenga legítimamente o otros datos remotos aceptados durante el uso normal. Primero construir un modelo de amenaza conciso de puntos de entrada realistas para atacantes remotos y fronteras de confianza, luego priorizar las rutas de código que involucren deserialización, análisis de YAML/JSON/protobuf, importaciones dinámicas/eval/ejecución de plantillas, extracción de archivos/archivos, redirecciones de autenticación, hooks de cliente generados, flujos de websocket/exec/attach/port-forward, y efectos de subprocesos o sistema de archivos. No asumas el control del atacante sobre kubeconfig local, argumentos de CLI, variables de entorno, plugins instalados, código fuente, credenciales, acceso privilegiado al clúster/admin, o ejecución de código previa; rechaza explícitamente los hallazgos que dependan de esas precondiciones. Antes de aceptar un candidato, busca archivos de hallazgos conocidos locales más problemas/PR abiertos actuales por duplicados, luego produce una prueba mínima segura que demuestre la ejecución de código controlada por el atacante o un primitivo RCE directo bajo la configuración normal indicada. Detente después de un problema crítico válido. Escribe el hallazgo en la carpeta ./findings/. Figura 2: El aviso creado por Codex de la figura 1 Encontramos que la mejor filosofía es gastar tantos tokens como necesites definiendo el resultado, y casi ninguno indicando al modelo cómo llegar allí. Si deseas que se encuentre el error mediante fuzzing, “usa fuzzing” es tan lejos como deberías ir. “Construye sobre mi arnés de fuzzing existente” o “construye un nuevo arnés de fuzzing” son ambas peores. Podría haber un arnés existente que sea igual de bueno. Un objetivo que prescribe el camino garantiza que Codex nunca tome otro, y pierdes el juicio y la resolución de problemas abiertos que hacen que /goal sea único. El lado del resultado requiere más cuidado porque debe estar calibrado. Si es demasiado específico, Codex no tiene suficiente para buscar y el valor de una ejecución autónoma de /goal no está claro. Cuando alimentamos a Codex la causa raíz exacta de un error conocido y le pedimos que encontrara variantes, no encontró nada. El alcance era demasiado estrecho. Cuando redujimos la entrada a una sola frase describiendo la clase de errores que debería buscar basada en el error conocido, surgieron numerosos errores. Reportamos 9 de ellos, con 3 ya corregidos y fusionados en upstream. Si un resultado es demasiado vago, el modelo proporciona salidas que no coinciden con lo que buscabas. Uno de los peores avisos de /goal que vimos durante Patch the Planet fue “encontrar errores en [X]”. El modelo no tenía forma de saber cuándo había terminado. Simplemente siguió ejecutándose, surfacing errores que no tenían impacto en el mundo real y desperdiciando tokens. Una definición completa del resultado también dice qué no cuenta como terminado. Los proyectos de código abierto en Patch the Planet tienen parte del código más auditado del mundo, y más de una vez /goal regresó con “sin errores encontrados”. Tratamos eso como un resultado intermedio, no como una condición de finalización, y escribimos persistencia en el propio objetivo. El recurso más efectivo para la caza de errores en /goal es un archivo THREAT_MODEL.md. Terminamos haciendo referencia a un archivo de modelo de amenaza en casi cada objetivo que ejecutamos porque define con precisión cómo lucen los errores válidos sin explicar cómo encontrarlos. Recomendamos que cada proyecto de código abierto cree uno. 3. Asignar un resultado por agente Poner dos resultados en competencia en un solo aviso de /goal resulta en una optimización desigual. Nos encontramos con esto repetidamente cuando un objetivo pedía tanto errores como cobertura. Cuando pusimos “encontrar errores” y “lograr alta cobertura” en el mismo aviso, la ejecución terminó haciendo uno de ellos mucho mejor que el otro. Esta fue nuestra experiencia al utilizar /goal para auditar zlib. Codex seguía gravitante hacia la misma parte del código, fuzzing las áreas que el modelo encontró primero sin llegar al resto. Nuestro instinto inicial fue corregir eso en el aviso añadiendo requisitos de cobertura, pero Codex entonces cambió su optimización a cobertura, y vimos una caza de vulnerabilidades poco impresionante. Lo que funcionó en su lugar fue mover completamente la cobertura fuera del aviso. Pedimos a Codex que primero identificara las cinco superficies de ataque más prometedoras después de revisar todo el código. Luego creamos una sesión de /goal separada para encontrar errores en cada sección. También agregamos una sesión completamente abierta junto a ellas para examinar las partes del código que los otros agentes no estaban asignados. Este enfoque funcionó drásticamente mejor. Figura 3: Los mantenedores de Rust asumieron que teníamos un equipo de ingenieros trabajando en encontrar errores. Solo era un ingeniero con un sólido dominio del /goal de Codex. Uno de nuestros ingenieros, Kevin Valerio, creó un sistema automatizado de análisis de variantes para el compilador Rust aprovechando /goal. Cada error de Rust que enviamos a través de Patch the Planet provino de él. P-critical es una etiqueta creada por los mantenedores de Rust para identificar errores que deben priorizarse para su corrección y fusión. El pipeline comenzó descargando cada problema etiquetado como P-critical en el repositorio rust-lang/rust como JSON. Un orquestador lee los problemas y genera un agente separado para cada uno. Un resultado por agente: en lugar de una única sesión que se le dice que realice análisis de variantes en cada error, el orquestador crea una sesión de Codex por problema, cada una ejecutando una tarea independiente para encontrar un solo resultado. Cada sesión se ejecuta en modo Goal con un aviso deliberadamente pequeño para encontrar un problema de seguridad con la misma causa raíz que el error original en P-critical. Recibe una descripción de una línea del riesgo en lugar de una causa raíz exacta con un rastreo completo, para que el modelo aún tenga la libertad de explorar más el código. Antes de que comience cualquier caza de variantes, una puerta de seguridad pregunta si el problema fuente es realmente una vulnerabilidad y lo dirige a saltar, no_variant o bug_found. Estamos utilizando eso para centrarnos en los errores P-critical más impactantes. Cada candidato pasa por un filtro de falso positivo en dos etapas. El primer juez verifica que el error represente un riesgo de seguridad genuino. El segundo, un modelo completamente diferente, realiza un pase centrado en PoC y exige que el problema pueda causar problemas de seguridad relevantes para el modelo de amenazas de Rust. Un candidato alcanza “hallazgo validado” solo si ambos pases están de acuerdo. Los hallazgos validados pasan por un último filtro humano. Se realiza una verificación de duplicados antes de que se abra cualquier cosa. Solo los errores que están confirmados en upstream y que no se hayan encontrado ya en el backlog de problemas de GitHub son redactados para su envío. Figura 4: El flujo de trabajo completo que Kevin Valerio utilizó para encontrar cada error en Rust Donde se necesita juicio humano Desde su lanzamiento, /goal ha sido una herramienta poderosa para amplificar el trabajo de caza de errores que hacemos. Codex puede crear infraestructura de seguridad personalizada que a un investigador de seguridad le lleva semanas construir en menos de un día. Puede revisar miles de líneas de código más rápido de lo que cualquier humano puede. /goal perseguirá fielmente cualquier resultado que le demos al modelo, lo que significa que la ejecución se decide en gran medida antes de que comience el modelo. Pero su efectividad aún depende de un experto que sepa dónde buscar, verificar que sus resultados cuenten como un hallazgo informable, y saber qué quieren ver los mantenedores del otro lado como divulgación válida de vulnerabilidad. La ingeniería de avisos es una gran parte de ello, pero solo puedes escribir un buen aviso si sabes exactamente lo que estás buscando.