Ir al contenido principal

El otro día me encontré con un programa que me permitía seleccionar de un conjunto de consultas pre-empaquetadas y luego se comunicaba con un servidor para recuperar la respuesta a la consulta seleccionada. Comencé a preguntarme cuando me di cuenta de que el programa nunca pidió una contraseña para la autenticación con el servidor. Resulta que la contraseña estaba incrustada en el programa. El autor explicó que estaba bien porque 1) era un archivo binario por lo que nadie podía leerlo y 2) si podían leerlo no podrían encontrar la cadena de la contraseña.

Ninguna de estas razones es válida y me gustaría usar este post para demostrarlo. Mi programa de ejemplo sólo escribe la "contraseña" en la terminal, pero la única diferencia con un programa de producción real es el número de cadenas que un usuario malicioso tendría que buscar.

#include <stdio.h>
#include <string.h>

main ()
{
char password [9] = {"secret"};

printf ("This is the password: %sn", password);

}
Figura 1 - Programa básico con contraseña incrustada

Cuando se ejecuta, muestra

x1
Esta es la contraseña: secreto
listo 14:12:16
Figura 2 - Ejecución del programa básico

Para mostrar las cadenas en el módulo del programa nuestro usuario malicioso puede usar el comando de las cadenas desde el directorio >system>gnu_library>bin. El -n5 limita la salida a cadenas de 5 caracteres o más. He truncado la salida (. . . .) para acortar la visualización pero se puede ver que la contraseña es una de las primeras cadenas que se muestran. Tener la contraseña cerca de palabras clave como "login" o "password" o de una identificación de usuario identificable como "admin", "root" o "sql" facilita la búsqueda.

>sistema>bin>cadena>cadenas -n5 x1.pm
bind, Release 17.1.beta.be
phx_vos#
Noah David. CAC
Pre-lanzamiento
Esta es la contraseña: %s
secreto
s$start_c_program
limpieza_preventiva
Salga.
. . . . .
Figura 3 - Usando el comando de cadenas GNU para encontrar todas las cadenas de más de 4 caracteres en el módulo de programa

Si el comando de las cadenas no está disponible, nuestro usuario malicioso sólo puede mostrar el módulo del programa. Sospecho que todos hemos hecho esto por accidente y aunque no es bonito, mostrará la contraseña. He vuelto a truncar la salida y de nuevo se puede ver la contraseña.

d x1.pm

SysAdmin>Noah_Davids>x1.pm 11-01-13 14:13:59 mst

`00`01`00`1Abind, Release 17.1.beta.be`00`00`00`00`00`00`00`04ctp
`00`00`00`00`0
+`00`00`00`00`00`00`00`00`00`00`00`00`00`00`00`00`00`00`00`00`00`00`00`0
0phx_vos
+#`00`00`00`00`00`00`00`00`00`00`00`00`00`00`00`00`00`00`00`00`00`00`00`
00`00 Noa
. . . .
+`00`00`00`00`00`00`00`00`00`00`00`00`00`00`00`00`00`00`00`00`00`00`00`C
D'`8B`C0
+Esta es la contraseña: %s
`00`00`00`00`00`00`00secret`00`00`00`00`00`00`00`04`B0`00`00`00`00`01`00
`00`00,`
+`00`00`04`00`00`00`03@`00`FF`F8`FF`FE`00`04main`00`00`83`EC`2C`C7D$$`00
. . . .
Figura 4 - Mostrando el módulo del programa para encontrar la contraseña

Hay varias alternativas para incrustar la contraseña en el programa.

La contraseña puede ser colocada en un archivo y el programa puede leer el archivo. Sólo las personas con "necesidad de correr" tienen acceso de lectura al archivo y todos los demás tienen acceso nulo. Por supuesto, "need to run" puede no equivaler a "need to know the password". Además, siempre existe el peligro de que alguien cambie el acceso por error.

Una alternativa es mantener la cadena de contraseñas en el programa y limitar el acceso al programa. Esta solución también sufre el problema de "es fácil cambiar una lista de acceso". Si el programa se mantiene en el mismo directorio que otros programas que pueden ser ejecutados por cualquiera, la probabilidad de un cambio de lista de acceso aumenta.

Finalmente, puedes mantener la contraseña en el módulo del programa pero ofuscar la cadena de alguna manera. El siguiente programa muestra una forma sencilla de hacerlo.

#include <stdio.h>
#include <string.h> 

main ()
{
char obfuscate [9] = {0x0c, 0x81, 0xe2, 0x94, 0xe6, 0x9c};
char key [9] = {127, 228, 129, 230, 131, 232, 133, 234, 135};
char password [9];
int i;

for (i = 0; i < strlen (obfuscate); i++)
    password [i] = obfuscate [i] ^ key [i];
password [i] = 0x0;
printf ("This is the password: %sn", password);
}
Figura 5 - Programa con cadena de contraseña ofuscada

Como puedes ver todo lo que hace es tomar los caracteres ofuscados y XOR con otro un conjunto de caracteres clave para crear la contraseña. Ejecutar el programa produce la misma salida que el primer programa.

x2
Esta es la contraseña: secreto
listo 14:12:51
Figura 6 - Ejecución del programa ofuscado

Pero una búsqueda de cadenas no muestra nada que se parezca a la contraseña

>sistema>bin>cadena>cadenas -n5 x1.pm
bind, Release 17.1.beta.be
phx_vos#
Noah David. CAC
Pre-lanzamiento
Esta es la contraseña: %s
s$start_c_program
limpieza_preventiva
Salga.
. . . .
Figura 7 - el comando de las cadenas ya no muestra la contraseña

Y mientras se muestra el archivo se muestran los caracteres de la contraseña ofuscados y los caracteres clave que hay que saber exactamente dónde buscar para encontrarlos y también cómo se combinan para crear la contraseña.

d x2.pm

SysAdmin>Noah_Davids>x2.pm 11-01-13 14:15:27 mst

. . . .
+`00`00`00`00`00`00`00`00`00`00`00`00`00`00`00`00`00`00`00`00`00`CD'`8B`
C0`00`0
+Esta es la contraseña: %s

`00`00`00`00`00`00`00`0C`81`E2`94`E6`9C`00`00`00`00`00`00`00`00`00`00`7F
`E4`81`
+E6`83`E8`85`EA`87`00`00`00`00`04`B0`00`00`00`00`01`00`00`00`00`00`00`0
4`01`B0
+`00`03@`00`FF`F0`00`08`FF`FE`00`04main`00`00`83`EC`89$X`89t$T`89|$P`C
7D$L`00
Figura 8 - El módulo del programa ya no muestra la contraseña reconocible

Esto todavía no es una solución perfecta ya que el módulo del programa puede ser desmontado para averiguar cómo se genera la contraseña. Aún así, desmontar el programa requiere mucha más sofisticación que mostrar el módulo del programa.

Estoy de acuerdo en poner la cadena de contraseñas ofuscadas en un archivo y luego proteger el archivo a través de una lista de acceso. Por un lado, si la contraseña necesita ser cambiada, es una solución mucho mejor que incrustar la cadena de contraseñas ofuscadas en el programa. Por otro lado sospecho que incluso si hay otras opciones de configuración en el archivo, poner la cadena en el archivo le dará a nuestro usuario malicioso menos cadenas de contraseñas potenciales para investigar. Por supuesto, todavía tendrá que acceder al archivo y luego tendrá que averiguar la técnica y la clave de ofuscación.

Un último punto, ¿cómo generé los caracteres ofuscados de la contraseña? Lo bueno de la operación XOR es que ((A XOR B) XOR B) es igual a A así que escribí un programa corto para tomar la contraseña original XOR los caracteres con mi clave e imprimir el resultado.

#include <stdio.h>
#include <string.h>

main ()
{
char password [9];
char key [9] = {127, 228, 129, 230, 131, 232, 133, 234, 135};
char newPW [9];
int i;

strcpy (password, "secret");
for (i = 0; i < strlen (password); i++)
    {
    newPW [i] = password [i] ^ key [i];
    printf ("%xn", newPW [i]);
    }
}
Figura 9 - Programa para generar la contraseña ofuscada