Aparentemente hay una vulnerabilidad (CVE-2014-6271) en bash: Bash ataque de inyección de código de variables de entorno especialmente diseñado
Estoy tratando de descubrir qué está sucediendo, pero no estoy completamente seguro de entenderlo. ¿Cómo se echo
puede ejecutar como está entre comillas simples?
$ env x='() { :;}; echo vulnerable' bash -c "echo this is a test"
vulnerable
this is a test
EDITAR 1 : Un sistema parcheado se ve así:
$ env x='() { :;}; echo vulnerable' bash -c "echo this is a test"
bash: warning: x: ignoring function definition attempt
bash: error importing function definition for `x'
this is a test
EDIT 2 : hay una vulnerabilidad / parche relacionado: CVE-2014-7169 que utiliza una prueba ligeramente diferente:
$ env 'x=() { :;}; echo vulnerable' 'BASH_FUNC_x()=() { :;}; echo vulnerable' bash -c "echo test"
salida sin parchear :
vulnerable
bash: BASH_FUNC_x(): line 0: syntax error near unexpected token `)'
bash: BASH_FUNC_x(): line 0: `BASH_FUNC_x() () { :;}; echo vulnerable'
bash: error importing function definition for `BASH_FUNC_x'
test
salida parcheada parcialmente (versión anterior) :
bash: warning: x: ignoring function definition attempt
bash: error importing function definition for `x'
bash: error importing function definition for `BASH_FUNC_x()'
test
salida parcheada hasta CVE-2014-7169 inclusive:
bash: warning: x: ignoring function definition attempt
bash: error importing function definition for `BASH_FUNC_x'
test
EDITAR 3 : la historia continúa con:
bash
shellshock
vulnerability
jippie
fuente
fuente
vulnerable
aparece en la salida. El principal problema es que bash también analiza y ejecuta el código después de la definición de la función. Vea la/bin/id
parte de seclists.org/oss-sec/2014/q3/650 para otro ejemplo.Respuestas:
bash almacena las definiciones de funciones exportadas como variables de entorno. Las funciones exportadas se ven así:
Es decir, la variable de entorno
foo
tiene los contenidos literales:Cuando se inicia una nueva instancia de bash, busca estas variables de entorno especialmente diseñadas y las interpreta como definiciones de funciones. Incluso puede escribir uno usted mismo y ver que todavía funciona:
Desafortunadamente, el análisis de definiciones de funciones a partir de cadenas (las variables de entorno) puede tener efectos más amplios de lo previsto. En versiones no parcheadas, también interpreta comandos arbitrarios que ocurren después de la terminación de la definición de la función. Esto se debe a limitaciones insuficientes en la determinación de cadenas de función aceptables en el entorno. Por ejemplo:
Tenga en cuenta que el eco fuera de la definición de la función se ejecutó inesperadamente durante el inicio de bash. La definición de la función es solo un paso para que la evaluación y la explotación sucedan, la definición de la función en sí y la variable de entorno utilizada son arbitrarias. El shell mira las variables de entorno, ve
foo
, lo que parece que cumple con las restricciones que conoce sobre cómo se ve una definición de función, y evalúa la línea, ejecutando involuntariamente también el eco (que podría ser cualquier comando, malicioso o no).Esto se considera inseguro porque las variables no suelen permitirse o esperarse, por sí mismas, que provoquen directamente la invocación de código arbitrario contenido en ellas. Quizás su programa establezca variables de entorno a partir de la entrada del usuario no confiable. Sería muy inesperado que esas variables de entorno pudieran manipularse de tal manera que el usuario pudiera ejecutar comandos arbitrarios sin su intención explícita de hacerlo utilizando esa variable de entorno por tal razón declarada en el código.
Aquí hay un ejemplo de un ataque viable. Usted ejecuta un servidor web que ejecuta un shell vulnerable, en algún lugar, como parte de su vida útil. Este servidor web pasa las variables de entorno a un script bash, por ejemplo, si está utilizando CGI, la información sobre la solicitud HTTP a menudo se incluye como variables de entorno del servidor web. Por ejemplo,
HTTP_USER_AGENT
puede configurarse según el contenido de su agente de usuario. Esto significa que si falsifica a su agente de usuario para que sea algo así como '() {:; }; echo foo ', cuando se ejecute ese script de shell,echo foo
se ejecutará. De nuevo,echo foo
podría ser cualquier cosa, maliciosa o no.fuente
export bar='() { echo "bar" ; }'; zsh -c bar
y se muestra enbar
lugar dezsh:1: command not found: bar
? ¿Estás seguro de que no estás confundiendo el shell que estás invocando con el shell que estás utilizando para configurar la prueba?Esto puede ayudar a demostrar aún más lo que está sucediendo:
Si está ejecutando un shell vulnerable, cuando inicie un nuevo subshell (aquí, simplemente usando la instrucción bash), verá que el código arbitrario (
echo "pwned"
) se ejecuta inmediatamente como parte de su inicio. Aparentemente, el shell ve que la variable de entorno (ficticio) contiene una definición de función y evalúa la definición para definir esa función en su entorno (tenga en cuenta que no está ejecutando la función: eso imprimiría 'hola').Desafortunadamente, no solo evalúa la definición de la función, sino que evalúa todo el texto del valor de la variable de entorno, incluidas las posibles declaraciones maliciosas que siguen a la definición de la función. Tenga en cuenta que sin la definición de la función inicial, la variable de entorno no se evaluaría, simplemente se agregaría al entorno como una cadena de texto. Como señaló Chris Down, este es un mecanismo específico para implementar la importación de funciones de shell exportadas.
Podemos ver la función que se ha definido en el nuevo shell (y que se ha marcado como exportada allí), y podemos ejecutarla. Además, el dummy no se ha importado como una variable de texto:
Ni la creación de esta función, ni nada de lo que haría si se ejecutara, es parte del exploit: es solo el vehículo mediante el cual se ejecuta el exploit. El punto es que si un atacante puede proporcionar código malicioso, precedido por una definición de función mínima y sin importancia, en una cadena de texto que se coloca en una variable de entorno exportada, entonces se ejecutará cuando se inicie una subshell, que es un evento común en muchos guiones Además, se ejecutará con los privilegios del script.
fuente
export
comando mientras que los otros teníanenv
? Estaba pensando queenv
se está utilizando para definir las variables ambientales que se llamarían cuando se inicie otro bash shell. entonces, ¿cómo funciona esto?export
env
yexport
definiciones de los entornos de exportación para que estén disponibles en un subnivel. El problema está en cómo se importan estas definiciones exportadas al entorno de una subshell, y específicamente en el mecanismo que importa las definiciones de funciones.env
ejecuta un comando con algunas opciones y variables de entorno establecidas. Tenga en cuenta que en los ejemplos de preguntas originales, seenv
establecex
en una cadena y llamabash -c
con un comando para ejecutar. Si lo haceenv x='foo' vim
, Vim se iniciará, y allí puede llamar a su shell / entorno que contiene!echo $x
, e imprimiráfoo
, pero si luego sale yecho $x
, no se definirá, ya que solo existió mientras vim se estaba ejecutando a través delenv
comando. En suexport
lugar, el comando establece valores persistentes en el entorno actual para que una subshell ejecutada más tarde los use.Escribí esto como una refundición estilo tutorial de la excelente respuesta de Chris Down arriba.
En bash puedes tener variables de shell como esta
Por defecto, estas variables no son heredadas por los procesos secundarios.
Pero si los marca para exportar, bash establecerá un indicador que significa que irán al entorno de subprocesos (aunque el
envp
parámetro no se ve mucho,main
en su programa C tiene tres parámetros:main(int argc, char *argv[], char *envp[])
donde esa última matriz de punteros es una matriz de variables de shell con sus definiciones).Entonces, exportemos de la
t
siguiente manera:Mientras que lo anterior
t
no estaba definido en la subshell, ahora aparece después de que lo exportamos (úseloexport -n t
si desea dejar de exportarlo).Pero las funciones en bash son un animal diferente. Los declaras así:
Y ahora puede invocar la función llamándola como si fuera otro comando de shell:
Una vez más, si genera una subshell, nuestra función no se exporta:
Podemos exportar una función con
export -f
:Aquí está la parte difícil: una función exportada como
fn
se convierte en una variable de entorno al igual que nuestra exportación de la variable de shellt
estaba arriba. Esto no sucede cuandofn
era una variable local, pero después de la exportación podemos verlo como una variable de shell. Sin embargo, puede también tener un (es decir, no la función) variable de regular de cáscara con el mismo nombre. bash distingue en función del contenido de la variable:Ahora podemos usar
env
para mostrar todas las variables de shell marcados para la exportación y tanto la regularidadfn
y la funciónfn
aparece:Un sub-shell ingiere ambas definiciones: una como variable regular y otra como función:
Puede definir
fn
como lo hicimos anteriormente, o directamente como una asignación de variable regular:Tenga en cuenta que esto es algo muy inusual. Normalmente definiríamos la función
fn
como hicimos anteriormente con lafn() {...}
sintaxis. Pero como bash lo exporta a través del medio ambiente, podemos "atajar" directamente a la definición regular anterior. Tenga en cuenta que (en contra de su intuición, tal vez) esto no da como resultado una nueva funciónfn
disponible en el shell actual. Pero si genera un shell ** sub **, entonces lo hará.Cancelemos la exportación de la función
fn
y dejemos el nuevo regularfn
(como se muestra arriba) intacto.Ahora la función
fn
ya no se exporta, pero la variable regular sífn
, y la contiene() { echo "direct" ; }
.Ahora, cuando una subshell ve una variable regular que comienza con
()
ella, interpreta el resto como una definición de función. Pero esto es solo cuando comienza un nuevo shell. Como vimos anteriormente, solo definir una variable de shell regular que comience()
no hace que se comporte como una función. Tienes que iniciar una subshell.Y ahora el error "shellshock":
Como acabamos de ver, cuando un nuevo shell ingiere la definición de una variable regular que comienza con
()
él, lo interpreta como una función. Sin embargo, si se da más después de la llave de cierre que define la función, también se ejecuta lo que esté allí.Estos son los requisitos, una vez más:
En este caso, un bash vulnerable ejecutará los últimos comandos.
Ejemplo:
La variable exportada regular
ex
se pasó al subshell, que se interpretó como una función,ex
pero los comandos finales se ejecutaron (this is bad
) a medida que se generaba el subshell.Explicando la elegante prueba de una línea
Una frase popular para probar la vulnerabilidad Shellshock es la que se cita en la pregunta de @ jippie:
Aquí hay un desglose: primero,
:
in bash es solo una abreviatura detrue
.true
y:
ambos evalúan a (lo adivinaste) verdadero, en bash:En segundo lugar, el
env
comando (también integrado en bash) imprime las variables de entorno (como vimos anteriormente), pero también se puede usar para ejecutar un solo comando con una variable (o variables) exportada dada a ese comando, ybash -c
ejecuta un solo comando desde su línea de comando:Entonces, al coser todo esto, podemos ejecutar bash como un comando, darle algo ficticio para hacer (como
bash -c echo this is a test
) y exportar una variable que comience con()
el subshell para interpretarlo como una función. Si shellshock está presente, también ejecutará inmediatamente los comandos finales en la subshell. Dado que la función que pasamos es irrelevante para nosotros (¡pero debe analizarse!) Usamos la función válida más corta imaginable:La función
f
aquí solo ejecuta el:
comando, que devuelve verdadero y sale. Ahora agregue a eso algún comando "malvado" y exporte una variable regular a una subshell y usted gana. Aquí está el one-liner nuevamente:Por
x
lo tanto, se exporta como una variable regular con una función válida simple conecho vulnerable
tachuelas al final. Esto se pasa a bash, y bash interpretax
como una función (que no nos importa) y luego quizás ejecuteecho vulnerable
if shellshock.Podríamos acortar un poco la línea eliminando el
this is a test
mensaje:Esto no molesta
this is a test
pero ejecuta el:
comando silencioso una vez más. (Si deja de lado,-c :
entonces se sienta en la subshell y tiene que salir manualmente.) Quizás la versión más fácil de usar sería esta:fuente
{ :;};
realmente dice. Esa sería una buena adición a su respuesta en mi opinión. ¿Puede explicar cómo pasa de su ejemplo al comando original en la pregunta?Si puede alimentar variables de entorno arbitrarias a un programa, puede hacer que haga casi cualquier cosa haciendo que cargue las bibliotecas de su elección. En la mayoría de los casos, esto no se considera una vulnerabilidad en el programa que recibe esas variables de entorno, sino más bien en el mecanismo por el cual un extraño puede alimentar variables de entorno arbitrarias.
Sin embargo, CVE-2014-6271 es diferente.
No hay nada de malo en tener datos no confiables en una variable de entorno. Uno solo tiene que asegurarse de que no se incluya en ninguna de esas variables de entorno que pueden modificar el comportamiento del programa. Ponga un poco más abstracto, para una invocación particular, puede crear una lista blanca de nombres de variables de entorno, que un extraño puede especificar directamente.
Un ejemplo que se ha presentado en el contexto de CVE-2014-6271 son los scripts utilizados para analizar archivos de registro. Esos pueden tener una necesidad muy legítima de pasar datos no confiables en las variables de entorno. Por supuesto, el nombre de dicha variable de entorno se elige de manera que no tenga ningún efecto adverso.
Pero esto es lo malo de esta vulnerabilidad de bash en particular. Se puede explotar a través de cualquier nombre de variable. Si crea una variable de entorno llamada
GET_REQUEST_TO_BE_PROCESSED_BY_MY_SCRIPT
, no esperaría que ningún otro programa además de su propio script interprete el contenido de esa variable de entorno. Pero al explotar este error bash, cada variable de entorno se convierte en un vector de ataque.Tenga en cuenta que esto no significa que se espera que los nombres de las variables de entorno sean secretos. Conocer los nombres de las variables de entorno involucradas no hace que un ataque sea más fácil.
Si las
program1
llamadasprogram2
que a su vez llamanprogram3
,program1
podrían pasar datos aprogram3
través de variables de entorno. Cada programa tiene una lista específica de variables de entorno que establece y una lista específica sobre la que actúa. Si elige un nombre que no reconoceprogram2
, puede pasar datos deprogram1
aprogram3
sin preocuparse de que esto tenga algún efecto adversoprogram2
.Un atacante que conozca los nombres exactos de las variables exportadas por
program1
y los nombres de las variables interpretadas porprogram2
no puede explotar este conocimiento para modificar el comportamiento de 'programa2' si no hay superposición entre el conjunto de nombres.Pero esto se rompió si se
program2
trataba de unbash
script, porque debido a este errorbash
interpretaría cada variable de entorno como código.fuente
Se explica en el artículo que ha vinculado ...
Lo que significa que el bash que se llama
-c "echo this is a test"
ejecuta el código en las comillas simples cuando se invoca.Significa que el ejemplo de código que publicó explota el hecho de que el bash invocado no deja de evaluar esta cadena después de realizar la asignación. Una asignación de función en este caso.
Lo realmente especial sobre el fragmento de código que publicó, según tengo entendido, es que al poner una definición de función antes del código que queremos ejecutar, se pueden eludir algunos mecanismos de seguridad.
fuente