Universidad Rey Juan Carlos Seguridad Informática Grado en Ingenierı́a Informática Pruba de control 1 Control de acceso y seguridad software Curso 2012–2013 Ejercicio 1 (1 punto) Contesta verdadero o falso a las siguientes preguntas. Cada respuesta correcta suma 0.25 y cada respuesta incorrecta resta 0.25 1. Una lista de control de acceso (ACL) tiene la ventaja que es fácil revocar los permisos de un determinado sujeto [V] [F] 2. Si el usuario alice:students ejecuta el programa -r-sr-xr-x grades.exe bob:professors a lo largo de la ejecución del programa adoptará temporalmente el UID del usuario bob:professors [V] [F] 3. Un requisito necesario para que ocurra una condición de carrera entre dos procesos es que uno de los dos se ejecute con privilegios de administración [V] [F] 4. El principio del privilegio mı́nimo consiste en prohibir la ejecución de cualquier programa con privilegios de administración [V] [F] Ejercicio 2 (1 punto) Explica brevemente en qué consiste un ataque por inyección SQL Ejercicio 3 (3 puntos) En un empresa de venta de material sanitario existen dos programas para la gestiı́on de la facturacı́on y para la gestión de los clientes. Los dos programas en cuestión son -rwxr-x--- /usr/bin/billing mgmt bill:billing -rwxr-x--- /usr/bin/customers mgmt cust:customers En el grupo billing está el usuario bill ası́ como todos los usuarios que trabajan con el programa billing mgmt. En el grupo customers está el usuario cust ası́ como todos los usuarios que trabajan con el programa customers mgmt Cada dı́a 5 del mes, los usuarios del grupo customers que usan customers mgmt necesitan algunos datos de facturación proporcionados por billing mgmt. Para ello, los desarroladores de la empresa han definido un sistema basado en intercambio de ficheros que utiliza el siguiente directorio drwxrwxr-x /home/share bill:billing En este directorio el programa billing mgmt escribe el siguiente fichero -rw-rw-r-- /home/share/billing data bill:billing Página 1 de 8 Hoja de Problemas 1 Control de acceso y seguridad software (a) (1.5 puntos) Contesta verdadero o falso a las siguientes preguntas, explicando brevemente el porqué de tu respuesta. Cada respuesta correcta suma 0.5 y cada respuesta incorrecta resta 0.5. Respuestas sin explicación no suman ni restan. El sistema de intercambio de ficheros definido por los desarroladores podrı́a poner en peligro . . . 1) La integridad de la información [V] [F] Sólo los usuarios del grupo billing pueden escribir el directorio /home/share o el fichero /home/share/data 2) La confidencialidad de la información [V] [F] Todos los usuario pueden leer el fichero /home/share/data 3) La disponibilidad de la información [V] [F] Sólo los usuarios del grupo billing pueden por ejemplo borrar el directorio /home/share o el fichero /home/share/data (b) (1.5 puntos) Modifica oportunamente el sistema de intercambio de ficheros para resolver los problemas identificados anteriormente. Para ellos es posible modificar permisos, usuario propietario y grupo propietario del directorio /home/share, del fichero /home/share/billing data y de los programas billing mgmt y customers mgmt Podemos hacer que todos los usuarios del departamento de facturación usen el programa /usr/bin/billing mgmt bill:billing como si fueran el usuario bill (usando el permiso SUID) -rwsr-x--- /usr/bin/billing mgmt bill:billing y modificar los permisos de la siguiente forma: drwxr-x--- /home/share bill:customers -rw-r----- /home/share/billing data bill:customers Otra opción es hacer los usuarios del grupo billing miembros del grupo customers y modificar los permisos de la siguiente forma: drwxrwx--- /home/share bill:customers -rw-rw---- /home/share/billing data bill:customers Página 2 de 8 Hoja de Problemas 1 Control de acceso y seguridad software Ejercicio 4 (5 puntos) Considera el siguiente código fuente: package system; public class Permission { private Resource resource; // Los permisos pueden ser ’-’, ’r’ o ’w’ // ’-’ significa ningún permiso, ’r’ lectura, ’w’ lectura y escritura // Los permisos están definidos para el propietario del recurso (permission[0]) // y para los otros usuarios (permission[1]) private char[] permission = new char[2]; protected void setResource(Resource resource){ this.resource = resource; } protected void setPermission(char[] permission){ for(int i = 0; i < permission.length; i++) this.permission[i] = permission[i]; } protected boolean denyReadPermission(int index){ if(index < 0 || index > 1) throw new RuntimeException(); if(permission[index] == ’-’) return true; return false; } protected boolean denyWritePermission(int index){ if(index < 0 || index > 1) throw new RuntimeException(); if(permission[index] == ’-’ || permission[index] == ’r’) return true; return false; } Página 3 de 8 Hoja de Problemas 1 Control de acceso y seguridad software package system; public class Monitor { private static HashMap<Resource, Permission> policy = new HashMap<Resource, Permission>(); public static void setPermission(Resource resource, char[] permission, int ownerID){ Permission p = new Permission(); p.setResource(resource); p.setPermission(permission); policy.put(resource, p); } public static HashMap<Resource, Permission> getPolicy(){ return policy; } public static void write(Resource r, int userID){ if(userID == r.getOwnerID() && !policy.get(r).denyWritePermission(0)) r.write(); else if(userID != r.getOwnerID() && !policy.get(r).denyWritePermission(1)) r.write(); } public static void read(Resource r, int userID){ if(userID == r.getOwnerID() && !policy.get(r).denyReadPermission(0)) r.read(); else if(userID != r.getOwnerID() && !policy.get(r).denyReadPermission(1)) r.read(); } } Página 4 de 8 Hoja de Problemas 1 Control de acceso y seguridad software package system; public class Resource { private int ownerID; private Object resource; protected Resource(int ownerID, Object resource){ this.ownerID = ownerID; this.resource = resource; } protected int getOwnerID(){ return ownerID; } protected Object getResource(){ return resource; } public void write(){ ... } public void read(){ ... } } package client; public class Session { //La variable ‘‘myUserID’’ se inicializa al crear ls sesión private final int myUserID; public final void setPermission(Resource r, char[] p); Monitor.setPermission(r, p, myUserID); } public final HashMap<Resource, Permission> getPolicy(){ return Monitor.getPolicy(); } public final void write(Resource r){ Monitor.write(r, myUserID); } public final void read(Resource r){ Monitor.read(r, myUserID); } Página 5 de 8 Hoja de Problemas 1 Control de acceso y seguridad software Existen dos paquetes, system y client. Las clases del paquete system modelan los recursos del sistema (Resource), los permisos (Permission) y el monitor de referencia (Monitor) que implementa la polı́tica de control de acceso. La aplicación prevé 3 tipos de permisos y dos tipos de usuarios. Los permisos están identificados por un char, donde ’-’ significa ningún permiso, ’r’ significa permiso de lectura y ’w’ significa permiso de lectura y escritura. Los usuarios pueden ser el propietario del recurso u otros usuarios. El tipo de permiso del propietario está almacenado en Permission.permission[0], mientras que el tipo de permiso para todos los demás está almacenado en Permission.permission[1]. El paquete system está “sellado” (sealed ), lo cual significa que nadie puede definir una clase que pertenezca a este paquete. Los usuarios interactúan con los recursos usando la clase Session del paquete client. Supongamos que la clase Session tenga funcionalidades para autenticar los usuarios y asignar por lo tanto un valor a la variable myUserID. Un usuario podrı́a desarrollar nuevas funcionalidades para la clase Session, pero no modificar los métodos ya definidos (que son declarados final) ası́ como el identificativo del usuario (myUserID). La clase Session permite invocar los métodos ofrecidos por la clase Monitor para fijar los permisos de un recurso (setPermission(Resource r, char[] p)), obtener la lista de permisos sobre todos los recursos (getPolicy()), leer (read(Resource r)) y escribir (write(Resource r)) recursos. (a) (2 puntos) Contesta verdadero o falso a las siguientes preguntas. Cada respuesta correcta suma 0.5 y cada respuesta incorrecta resta 0.5 1) El control de acceso implementado por este código es control de acceso discrecional [V] [F] 2) Un desarrollador puede definir nuevos métodos en la clase Session para . . . 2.a) . . . invocar directamente el método setPermission(char[] permission) de la clase Permission [V] [F] 2.b) . . . invocar directamente el método read() de la clase Resource [V] [F] 2.c) . . . crear recursos invocando el contructor Resource(int ownerID, Object resource) [V] [F] (b) (3 puntos) Identifica los fallos de este código fuente, tanto los que podrı́an causar un mal funcionamiento del programa como los que representan un peligro para la seguridad del programa. Para cada uno de ellos, describe a) en qué consiste el fallo, b) qué problema puede causar al programa y c) cómo se podrı́a modificar el código fuente para solucionar el fallo. Página 6 de 8 Hoja de Problemas 1 Control de acceso y seguridad software Solución 1. La clase Permission no comprueba si la longituda del array permission pasado como parametro es 2, por lo tanto podrı́a causar una excepción. Para resolver el fallo hay que manejar explicitamente este caso, por ejemplo ejecutando algo tipo if(this.permission.length != permission.length) return; antes de copiar los permisos. 2. La clase Permission no comprueba que los char contenidos en el array permission pasado como parametro sean los que el programa espera, es decir, ’-’, ’r’ o ’w’. Este fallo podrı́a causar un mal funcionamiento en la gestión de los permisos. Para resolver el fallo hay que comprobar los tipos de permisos que se está intentando copiar, por ejemplo ejecutando algo tipo for(char c in permission) if(c != ’-’ || c != ’r’ || c != ’w’) return; antes de copiar los permisos. 3. Los métodos denyReadPermission() y denyWritePermission() ejecutan el control de acceso en base a la denegación del acceso, no a la autorización. Si un atacante se aprovecha del fallo definido anteriormente y pone como permiso un char que no sea ’-’, ’r’ o ’w’, el método siempe devuelve false, lo cual implica que el acceso es garantizado. Para resolver el fallo es necesario comprobar si un usuario tiene acceso. Por ejemplo el método denyReadPermission() se deberı́a cambiar en grantReadPermission() de esta manera protected boolean grantReadPermission(int index){ if(index < 0 || index > 2) throw new RuntimeException(); if(permission[index] == ’r’ || permission[index] == ’w’) return true; return false; } 4. El método setPermission(Resurce resource, char[] permission, int ownerID) no comprueba que el ownerID del recurso resource coincida con el ownerID pasado como parametro. Aprovechando de este fallo un usuario podrı́a fijar los permisos de un recurso que no le pertenece. Para resolver el fallo habrı́a que ejecutar if(resource.getOwnerID() != ownerID) return; Página 7 de 8 Hoja de Problemas 1 Control de acceso y seguridad software antes de crear el objeto Permission que define la polı́tica de control de acceso sobre el recurso. 5. El método getPolicy() de la clase Monitor devuelve un objeto mutable (la HashMap con las parejas recursos-permisos). Un atacante podrı́a modificar la politica de control de acceso, por ejemplo eliminando elementos de la HashMap. Para resolver el fallo habrı́a que modificar el método getPolicy() de esta manera public static HashMap<Resource, Permission> getPolicy(){ return Collections.unmodifiableMap(policy); } 6. Los métodos read() y write() de la clase Resource son declarados public. Cualquier usuario que acceda a la lista de recursos, invocando el método getPolicy(), podrı́a leer y escribir los recursos saltándose la polı́tica de control de acceso ejecutada por la clase Monitor, que supuestamente deberı́a vigilar cualquier acceso a los recursos. Para resolver el fallo habrı́a que declarar ambos métodos como (por lo menos) protected. 7. Aun ası́, el modificador protected usado en la clase Permission no impide que alguien cree en un paquete distinto de system una clase que extienda Permission y pueda invocar todos los métodos declarados protected. Lo mismo vale para Resource. Habrı́a que declararlos package − private (es decir, ningún modificador de visibilidad). De esta manera sólo las clases del paquete system pueden acceder a estos métodos, y dado que el paquete está sellado ninguna clase más podrı́a acceder. 8. En general la clase Monitor, que es la interfaz entre los usuarios que usan la clase Session y las clases del paquete system no ha sido programada de manera defensiva. Por ejemplo, en setPermission(), write() y read() no comprueba que el recurso que se pasa es distinto de null. La istrucción policy.get(r).denyWritePermission() en el método write() lanzarı́a una excepción si el resultado de policy.get(r) fuera null (p.e., si el recurso r no existe). Página 8 de 8