Archivo

Entradas Etiquetadas ‘ps’

Ocultar los parámetros de nuestro proceso a ps

Martes, 11 de Octubre de 2011 Gaspar Fernández Sin comentarios

password_flickrEn ocasiones, estamos desarrollando una aplicación, y ésta necesita que le pasemos como parámetro, por ejemplo, una contraseña. El gran peligro que esto tiene es que cualquier usuario, pidiendo un listado de procesos con ps podrá ver la contraseña.

Imaginemos que tenemos una aplicación (que hemos hecho nosotros) que conecta con un servidor, y dado que hemos hecho un script para automatizar el proceso, el nombre de usuario y contraseña los pasaremos como parámetro al ejecutable. Dicho proceso se llama “aplicacionsegura”, dicho programa lo hemos lanzado en un servidor y otros usuarios tendrán acceso a dicha máquina. Ahora uno de ellos ejecuta lo siguiente:

$ ps ax
….
10560 pts/3    S+     0:00 ./aplicacionsegura –user=usuario –passwd=micontraseña

¡Nuestro gozo en un pozo! Otro usuario ya tiene nuestra contraseña, y ha sido muy sencillo. Y además lo podremos ver (de hecho ps es lo que hace) viendo el archivo /proc/PID/cmdline. Aunque debemos ver qué opciones tenemos:

Modificar el parámetro passwd

Para ilustrar el ejemplo, vamos a fijar la posición de –passwd=xxxxx al segundo parámetro (la captura de parámetros no es objeto de este post). Lo primero que vamos a probar es introducir un terminador en las cadenas de los parámetros, Si la cadena empieza por ‘\0′ estará vacía:

1
2
3
4
...
argv[1][0]='\0';
argv[2][0]='\0';
....

Aunque tardaremos poco en darnos cuenta que da igual, por una parte, no podríamos borrar todos los rastros de información, ya que si escribimos en la posición 0 de la cadena “–passwd=micontraseña” un terminador, el resto de la cadena se quedará en memoria y podrá ser leída. De todas formas, la cadena parece que sólo tiene un espacio para ps, es más, el \0 le ha dado igual.

Probemos ahora escribiendo “HOLA” en la cadena de la contraseña (ahora sí pongo el código completo, test.c):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

int main(int argc, char *argv[])
{
  /* Reservamos memoria de sobra */
  char password[40];
  char usuario[40];

  if (argc<3)
    {
      fprintf(stderr,"Debe tener dos parámetros:\n%s --user=USUARIO --passwd=CLAVE\n", argv[0]);
      return EXIT_FAILURE;
    }

  /* Esto es un simple ejemplo, vamos a quitar --user y --passwd de una forma fea */

  /* Copiamos el usuario en otra variable */
  strcpy(usuario, argv[1]+7);   /* +7, para eliminar --user= (7 caracteres) */

  /* Copiamos la contraseña en otra variable */
  strcpy(password, argv[2]+9);  /* +9, para eliminar --passwd= (9 caracteres) */

  strcpy(argv[2]+9, "HOLA"); // EN LA CLAVE PONEMOS "HOLA"

  printf("user: %s ; pass: %s", usuario, password);
  /* Esperamos una tecla para terminar (sólo para que no se cierre demasiado rápido */
  /* y nos dé tiempo a mirar la información de ps */
  getchar();
  return EXIT_SUCCESS;
}

Ahora ejecutaremos lo siguiente:

$ gcc -o test test.c
$ ./test & # El programa test esperará una tecla para terminar, pero lo ejecutaremos de fondo, para que no se cierre.
$ ps ax
….
10809 pts/3 S+ 0:00 ./test –user=usuario –passwd=HOLA traseña
….
$ killall test # Para matar el proceso

Un efecto curioso, las cadenas de los parámetros no son NULL-terminated, de cara a /proc/PID/cmdline por lo que cuando ponemos un terminador, lo toma como un espacio. Y se ve parte del parámetro. Lo que sí podemos hacer es sustituir por asteriscos, tantos asteriscos como letras tenga el parámetro.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

void rellenaConAsteriscos(char *cadena);

int main(int argc, char *argv[])
{
  /* Reservamos memoria de sobra */
  char password[40];
  char usuario[40];

  if (argc<3)
    {
      fprintf(stderr,"Debe tener dos parámetros:\n%s --user=USUARIO --passwd=CLAVE\n", argv[0]);
      return EXIT_FAILURE;
    }

  /* Esto es un simple ejemplo, vamos a quitar --user y --passwd de una forma fea */

  /* Copiamos el usuario en otra variable */
  strcpy(usuario, argv[1]+7);   /* +7, para eliminar --user= (7 caracteres) */

  /* Copiamos la contraseña en otra variable */
  strcpy(password, argv[2]+9);  /* +9, para eliminar --passwd= (9 caracteres) */

  rellenaConAsteriscos(argv[1]+7);
  rellenaConAsteriscos(argv[2]+9);

  printf("user: %s ; pass: %s", usuario, password);
  /* Esperamos una tecla para terminar (sólo para que no se cierre demasiado rápido */
  /* y nos dé tiempo a mirar la información de ps */
  getchar();
  return EXIT_SUCCESS;
}

void rellenaConAsteriscos(char *cadena)
{
  while (*cadena!='\0')
    *(cadena++)='*';
}

Ahora al ejecutar ps:

$ ps ax

10906 pts/3 S+ 0:00 ./test –user=******* –passwd=*************

Aunque esta forma revela en cierto modo la longitud de las contraseñas y el nombre de usuario, puede que no nos interese, que queramos eliminar el parámetro entero y que no se vea:

La manera rápida pero peligrosa y de andar por casa

El objetivo es escribir algo más largo que el último parámetro. Es decir, si el parámetro de contraseña tiene 22 letras, tenemos que escribir algo más grande, unas 23 letras, o cargarnos el terminador del segundo argumento (no son NULL-terminated, el kernel sabe dónde empieza y dónde termina la cadena, pero hay un NULL para comprobar que todo va bien).

En este caso podemos hacer:

1
strcpy(argv[2]+9, "Esto es una cadena muy grande para ver si cargándome el segundo parámetro desaparece toda la información");

y veremos cómo ps no nos dice nada, en principio no es demasiado elegante, nos estamos cargando un terminador, que nosotros podríamos necesitar, para lectura, y estamos escribiendo en una zona de memoria que no es nuestra, ya que el argumento tiene reservado un tamaño de memoria, y estamos escribiendo más de lo que debemos (podemos producir una violación de segmento).

Decirle al kernel que no queremos los parámetros

Parecida a la forma anterior, podemos hacer:

1
argv[2][strlen(argv[2])]=' ';

lo que no es intuitivo para nada, porque nos estamos cargando el terminador, que controla el paso de parámetros. De esta forma, no tendremos ningún parámetro. Tambén podemos hacer una forma general

1
argv[argc-1][strlen(argv[argc-1])]=' ';

De esta forma desaparecerán todos los argumentos de /proc/PID/cmdline ; sólo tendremos la ruta y el nombre del ejecutable, y nuestros datos, al menos por esta parte, estarán seguros.
Foto: marc falardeau (Flickr)

Documentando el código con Doxygen

Domingo, 11 de Abril de 2010 Gaspar Fernández Sin comentarios

librosssTanto o más importante que tirarse horas programando una aplicación es su documentación, y debemos hacerlo aunque nosotros seamos los únicos que intervengamos en su desarrollo.
Algo que siempre digo en mis clases de programación es que a poco que compliquemos el código si no comentamos lo que estamos haciendo, en séis meses cuando toque hacer una siguiente versión no tendremos ni idea de lo que hace; y esto conlleva pasar más tiempo para hacer las modificaciones que necesitamos, que al final se traducen en dinero.

Doxygen es una de esas herramientas que nos hacen la vida más fácil, ya que analizará los comentarios de nuestros archivos fuente y generará un documento (html, latex…) con todas las clases, funciones, métodos, variables globales, definiciones, etc que contenga nuestro código; se generará un documento muy valioso para hacer futuras modificaciones.

Este programa tiene multitud de opciones y palabras clave que podemos ver en su documentación. Pero yo comentaré lo justo para empezar, ya que no queremos perder mucho tiempo y queremos empezar a documentar código. Hay muchos lenguajes soportados, pero tanto para C, C++, PHP y algunos otros podemos hacer comentarios con /* …. */ o //, pues bien, Doxygen leerá los comentarios que comiencen por /** (barra, asterisco, asterisco) o /// (tres barras). Lo que situemos como comentario será la descripción de la función, clase, método, o lo que sea que pongamos detrás; así como la descripción del propio fichero que pondremos como primer comentario al principio de nuestro código.

Para Doxygen existen algunas palabras clave como por ejemplo:

  1. @file : Especifica el propio fichero que editamos, útil para la descripción del fichero.
  2. @brief : Breve descripcion de la función, método, clase, variable… que estamos describiendo.
  3. @date : Fecha
  4. @author : Autor
  5. @version : Versión
  6. @param : Parámetro (en caso de funciones y métodos)
  7. @return : Valor de la salida (en caso de funciones y métodos)

Propongo un pequeño código en PHP que no hace nada, pero que se documentará bien:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
<?php
 /**
******************************************************
*  @file test.php
*  @brief Breve descripción
* Pequeña documentación del archivo
* @author Gaspar
* @version 2.0
* @date Marzo 2010
*
*
*******************************************************/


/**
* Variable global
*/

$var_global='VALOR';

/** Ahora me da por definir cosas */
define('defino_algo', 'DEFINICION');
/*
* Description: Esta función algo hará
*
* @param $cadena
* Esto es una cadena graciosa
* @param $vector
* Esto es un vestor gracioso
*
* @return string
* Cadena resultante

*/

function estoyprobando($cadena, $vector)
{
}

/**
******************************************************
* @brief Clase para hacer pruebas
*
******************************************************/

class TestingPHP
{
/**
*************************************************************
* @brief Constructor
*************************************************************/

function __construct()
{
}

/**
*************************************************************
* @brief Metodo 1
* @param $par Primer parametro de entrada
*
* @return Genero una salida
*************************************************************/

function metodo1($par)
{

}
};
?>;

Para documentarlo con Doxygen, tendremos que hacer lo siguiente:

$ doxygen -g testing.cfg

Generaremos un archivo de configuración de la documentación de ejemplo, sólo tendremos que cambiar unas cuantas cosas para generar la documentación como nosotros queramos:

  • PROJECT_NAME=Miproyecto (una sóla palabra)
  • PROJECT_NUMBER=0.2 (la versión)
  • OUTPUT_DIRECTORY=doc (Directorio donde irá la documentación)
  • OUTPUT_LANGUAGE=Spanish (Queremos documentación en español
  • EXTRACT_ALL= YES (Incluso lo que no esté documentado aparecerá en la documentación
  • EXTRACT_PRIVATE=YES (Extraeremos los métodos públicos)
  • EXTRACT_STATIC= YES (Extraeremos los métodos estáticos)
  • RECURSIVE= YES (Extracción recursiva, incluiremos los subdirectorios)
  • CREATE_SUBDIRS=YES (Creará subdirectorios a la hora de documentar, es importante si tenemos muchas líneas de código fuente (muchas funciones, clases, archivos….) ya que de otra forma situará todos los archivos de la salida en el mismo directorio, y pueden ser muchos.)
  • FILE_PATTERNS = *.php3 *.php *.c *.cpp (Todas las extensiones de nuestros archivos fuente)
  • PDF_HYPERLINKS= YES (Crearemos una salida LaTeX con enlaces que se exportarán a PDF)
  • HAVE_DOT=YES (Crearemos mejores gráficos de clases)

Tras ello hacemos:

$ doxygen testing.cfg

Tendremos en el directorio doc toda la documentación de nuestra aplicación.

Foto: br1dotcom (Flickr)

Visita otras webs de la red