Categories
PHP Quiz Seguridad

Ejercicio de la Semana: Login de usuarios y actualización de datos

A partir de ahora, cada semana haré el intento de poner los quiz los días lunes o martes, así tendremos más tiempo para comentar estos pequeños ejercicios.

Esta vez, se trata de dos páginas: la primera que se encarga de realizar el login de los usuarios y la segunda se encarga de mostrar y actualizar el perfil del usuario que accede a la página.

php:

<?php
session_start();

/*
 session.php:
  Se encarga de validar los datos del usuario y
  que exista una sesión válida para acceder a user.php
*/

include_once './config.php';
include_once './db.php';

if ( !empty($_REQUEST['action']) ) {
        switch ($_REQUEST['action']) {
                case 'login':
                        if ( !empty($_SESSION['user']) ) {
                                header('Location: http://sitio/user.php');
                                exit();
                        }
                       
                        $username = $db->escape($_POST['user']);
                        $pass = md5($secret_key . $_POST['password']);
                       
                        if ( $user = $db->get_row("SELECT * FROM users WHERE user='$username' AND password='$pass'") ) {
                                session_regenerate_id();
                                $_SESSION['user'] = $user;
                                header('Location: http://sitio/user.php');
                                exit();
                        }
                        die('Usuario no válido');
                case 'logout':
                        // ...
        }
}

?>

php:

<?php
/*
 user.php:
   Se encarga de mostrar y actualizar el perfil de un usuario
*/

include_once './session.php';

if ( empty($_SESSION['user']) ) {
        header('Location: http://sitio/session.php');
        exit();
}

if ( !empty($_REQUEST['action']) ) {
        switch ($_REQUEST['action']) {
                case 'update-profile':
                       
                        // Limpiar los datos
                        $_POST['name'] = htmlspecialchars(strip_tags($_POST['name']), ENT_QUOTES, 'utf-8');
                        $_POST['email'] = preg_replace('/[^a-z0-9.@-]/i', '', $_POST['email']);   

                        // Escapar los valores
                        $user = $db->escape($_SESSION['user']->user);
                        $name = $db->escape($_POST['name']);
                        $email = $db->escape($_POST['email']);
                        $password = md5($secret_key . $_POST['password']);
                       
                        $sql = "UPDATE users SET name = '%s', email = '%s', password = '%s' WHERE user = '%s'";
                       
                        $db->query(sprintf($sql, $name, $email, $password, $user));
                       
                        break;
                case 'recover-password':
                        // ...
        }
}

?>

¿Existe algún bug en el código mostrado?

Actualización:

  1. Cambio de $_POST['user'] por $_SESSION['user']->user en user.php
  2. Cambio de ubicación de la comprobación de la variable user en la sesión

¿Todavía queda algún problema de seguridad?

Categories
Seguridad WordPress

Cuidado con la codificación de los datos

En el anterior quiz, había puesto un bug existente en versiones anteriores de WordPress que permitía hacer SQL Injection.

Como agusti comentó, el problema se presenta al aplicar la función mysql_real_escape_string antes de hacer la conversión de un juego de caracteres X a UTF-8.

mysql_real_escape_string: Escapa todos los caracteres especiales en la cadena_no_escapada, tomando en cuenta el juego de caracteres actual de la conexión, de tal modo que sea seguro usarla con mysql_query()

Pues bien, para hacer posible el ataque es necesario usar un juego de caracteres en los que ' o \ puedan ser expresados como una secuencia de caracteres seguros; uno de éstos es UTF-7, ya que ' puede ser representado como +ACc- y \ como +AFw-.

Para obtener esas secuencias, pueden hacerlo manualmente en base a la documentación sobre UTF-7 o usando esta simple función:

php:

<?php
$table = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";

function mb64($match) {
    global $table;
   
    return $table[bindec($match[0])];
}
function utf7_char($char) {
    $bin = str_pad(decbin(ord($char)), 16, 0, STR_PAD_LEFT) . '00';
   
    return '+' . preg_replace_callback('/\d{6}/', 'mb64', $bin) . '-';
}
echo utf7_char("'");
?>

Ahora con las herramientas necesarias, lo único que queda es empezar a jugar con la consulta para obtener los resultados deseados, por ejemplo con los siguientes valores obtenemos todas las entradas (notar que sólo se necesita evadir '):

  • title=+ACc- or 1=1--+ACc- (equivale a ' or 1=1--')
  • charset=utf-7

Se deja como tarea para el lector probar otras consultas 🙂

Categories
Seguridad WordPress

Exploit para versiones de WordPress menores a 2.0.5

Si todavía eres uno de los que no ha migrado a la versión 2.0.6 de WordPress, es mejor que lo hagas cuanto antes, puesto que ha sido liberado el exploit que aprovecha las vulnerabilidades existentes en versiones anteriores (<= 2.0.5).

Este exploit obtiene las cookies (usuario y password) necesarios para entrar en un sitio vulnerable -con extensión mbstring habilitada y wordpress <= 2.0.5.

Categories
Varios

¿Cuántas entradas diarias publicaban en sus inicios?

La presentación de un nuevo integrante de Planet Webdev, quien al parecer anda algo preocupado por el escaso contenido que generó en sus primeros días, me hizo acordar los inicios de este blog, cuando a duras penas -entre tres personas- publicábamos de 0 a 6 entradas mensualmente.

Es así que por ejemplo que durante el 2005 publicamos la exorbitante cifra de 22 artículos :D. Si alguién siguió la evolución de este blog desde sus inicios -a parte de nosotros claro :)-, se dará cuenta que ahora se publica un poco más seguido, pero el formato de las entradas ha cambiado -lamentablemente ya no se publican extensos y detallados tutoriales.

Y ustedes: ¿qué tanto escribían cuando se iniciaron como bloggers?

Categories
Quiz Seguridad Web WordPress

Un bug interesante en WordPress

El presente quiz está basado en un reciente bug de WordPress que fue corregido en la versión 2.0.6 de este CMS

php:

<?php

header('Content-type: text/plain; charset=utf-8;');

if ( empty($_POST['title']) ) {
        die('Parámetros no válidos');
}

// Conexión a la base de datos test
mysql_connect('localhost', 'root', '1234');
mysql_select_db('test');

// Escapar los valores
$title = mysql_real_escape_string($_POST['title']);

// Hacer la conversión si se envía el parámetro charset
if ( !empty($_POST['charset']) ) {
        // Verificar si la extensión mb_string está habilitada
        if ( function_exists('mb_convert_string') ) {
                $title = @mb_convert_encoding($title, 'UTF-8', $_POST['charset']);
        }
        // Verificar si la extensión iconv está habilitada
        elseif ( function_exists('iconv') ) {
                $title = @iconv($_POST['charset'], 'UTF-8', $title);
        }       
}

$sql = "SELECT * FROM wp_posts WHERE post_title = '$title'";

if ( $result = mysql_query($sql) ) {
        while ($row = mysql_fetch_assoc($result)) {
                print_r($row);
        }
       
        mysql_free_result($result);
}

/*
        Muestra el error intencionalmente
*/

if ( $error = mysql_error() ) {
        echo "MySQL: $error\nConsulta: $sql";
}

mysql_close();
?>

¿Dónde se encuentra el error? y ¿cómo explotarlo? (Si desean puedo colgar una página para que hagan las pruebas)