Contenido principal

Solución Reto #3: LSB

Marzo 16, 2009

Mucho antes de vencerse el plazo para resolver el reto, finalmente hubo un ganador!, el primer ganador de esta serie de retos. A continuación publico la solución tal cual fue enviada a mi correo por kmykc


Solución oficial por kmykc


BOF<<
Vamonos por partes, este reto lo pude resolver en gran medida gracias a la ayuda de HaDeS, como veran en el post en el cual publico el reto dejo una pequeña ayuda despues de que le pedi una pista. Analizemos esos pasos que dio y la forma de ir codificando para lograr conseguir el reto.

El procedimiento es el siguiente:
1.- Elaborar un programa que lea cada pixel de la imagen.
2.- A cada pixel extraer su respectivo RGB.
3.- A cada color extraer el bit menos significativo y agruparlos cada 8 bits, para formar un byte
4.- El byte enviarlo a un archivo

Esos pasos para la primera parte, la segunda parte es mucho más fácil, solo tenes que usar el software mp3stego, y la clave la podes
encontrar en naranjito.

Veamos los puntos:

1.- Elaborar un programa que lea cada pixel de la imagen.

//Cargamos la referencia a la imagen.
$im = imagecreatefrompng("stego.png");

//Recorremos cada pixel de la imagen como si fuera una matriz bidimencional, recogiendo los datos de cada pixel.
for($y=0;$y<imagesy($im);$y++) {
 for($x=0;$x<imagesx($im);$x++) {
 
  //Obtener el valor de cada pixel mezclado por los colores rojo, verde y azul (rgb)
  $rgb = imagecolorat($im, $x, $y);
 }
}

2.- A cada pixel extraer su respectivo RGB.

 //Ahora obtenemos el nivel de cada color: rojo, verde y azul (Nota 1)
 $r = ($rgb >> 16) & 0xFF; //Desplazamiento de 16 bits a la derecha y hacemos una operacion AND con 0xFF
 $g = ($rgb >> 8) & 0xFF;  //Desplazamiento de 8 bits a la derecha y hacemos una operacion AND con 0xFF
 $b = $rgb & 0xFF;         //Hacemos una operacion AND con 0xFF

(Nota 1)
Hare una breve explicacion de esto para que se entienda mejor.
El operador ">>" nos indica un desplazamiento de bits, el color puede ir de 0 a 255 para rojo, verde y azul, tenemos algo asi:

	Decimal:	   255     255      255
	Binario:	11111111 11111111 11111111
	Color  :	   rojo    verde    azul

Cuando obtenemos (o sacamos) cada color hacemos esto:
Como ejemplo tenemos el valor: 1123712 (Valor binario: 100010010010110000000) y un desplazamiento de 8 bits.

pixel:
100010010010110000000
Operacion:
pixel >> 8
Lo que sucede:
000000001000100100101
pixel nuevo:
1000100100101

Realizamos la operacion & (AND) la cual dice que el resultado de dicha operacion entre bits nos dara "1" si y solo si los dos valores comparados son "1".

Ahora hacemos: pixel nuevo & 0xFF (Valor binario: 11111111)

Operacion:
1000100100101
0000011111111 (OJO, los primeros bits como no tienen valor se llenan con "ceros").
--------------
0000000100101

Quedando el nuevo valor como: 100101 (37 decimal), que en este caso representa el verde, si hacemos la misma operación con >> 16, representaría el rojo, y si sólo hicieramos la operación AND obtendríamos el azul.
(FIN NOTA 1)

3.- A cada color extraer el bit menos significativo y agruparlos cada 8 bits, para formar un byte

Una vez obtenido el valor lo convertimos a binario, ya que el resultado lo regresa en decimal, solo hacemos esto:

 //OBTENIENDO EL VALOR BINARIO
 $rBin = decbin($r);
 $gBin = decbin($g);
 $bBin = decbin($b);
 
 //Extraemos el bit menos significativo de cada valor obtenido
 $rBinNew = substr($rBin,-1);
 $gBinNew = substr($gBin,-1);
 $bBinNew = substr($bBin,-1);
 
 //Por ultimo vamos guardando los 3 valores binarios (concatenandolos) en una variable
 $rgbBinNew .= $rBinNew.$gBinNew.$bBinNew;

4.- El byte enviarlo a un archivo

Una vez que tenemos todos los bits en la cadena "$rgbBinNew", lo agrupamos de 8 en 8 para formar el byte y enviarlo al archivo.

 //Obtenemos la longitud de la nueva cadena.
 $longi = strlen($rgbBinNew);
 
 /*En este ciclo el incremento sera de 8 para formar el byte.
  *Procedimiento:
  *
  *Cada bit se ira guardando en una variable auxiliar ($aux) dentro del for anidado.
  *Cuando sale del for anidado se convierten los 8 bits en un valor decimal (Funcion: bindec()) y despues se convierte
  *a caracter (Funcion: chr()), por ultimo escribimos dicho caracter en un archivo.
  */
 for($i=0;$i<$longi;$i+=8) {
  $aux = "";
  for($j=0;$j<8;$j++) {
   $aux .= $rgbBinNew[$i+$j];
  }
  $aux = bindec($aux);
  $aux = chr($aux);
 
  fputs($archivo, $aux);
 }

El codigo completo queda de la siguiente manera:

<?php
$im = imagecreatefrompng("stego.png");
$archivo = fopen("salida","w");
$rgbBinNew = "";

for( $y = 0; $y < imagesy( $im ); $y++ ) {
 for( $x = 0; $x < imagesx( $im ); $x++ ) {
  //OBTENER EL VALOR DE CADA PIXEL
  $rgb = imagecolorat( $im, $x, $y );
 
  //OBTENIENDO LOS COLORES R, G, B
  $r = ($rgb >> 16) & 0xFF;
  $g = ($rgb >> 8) & 0xFF;
  $b = $rgb & 0xFF;
 
  //OBTENIENDO EL VALOR BINARIO
  $rBin = decbin($r);
  $gBin = decbin($g);
  $bBin = decbin($b);
 
  //OBTENEMOS EL BIT MENOS SIGNIFICATIVO
  $rBinNew = substr($rBin,-1);
  $gBinNew = substr($gBin,-1);
  $bBinNew = substr($bBin,-1);
 
  //GUARDAR LOS TRES VALORES BINARIOS EN UNA CADENA Y GUARDARLO EN UN ARCHIVO
  $rgbBinNew .= $rBinNew.$gBinNew.$bBinNew;
 }
}

$longi = strlen($rgbBinNew);
for($i=0;$i<$longi;$i+=8) {
 $aux = "";
 for($j=0;$j<8;$j++) {
  $aux .= $rgbBinNew[$i+$j];
 }
 $aux = bindec($aux);
 $aux = chr($aux);
 
 fputs($archivo, $aux);
}

imagedestroy($im);
fclose($archivo);
?>

LISTO !!!, hemos conluido con la primer parte la cual es, a mi parecer, la mas complicada. Ahora veamos una pequeña parte del archivo de salida, esto lo podemos hacer con algun editor hexadecimal, en mi caso utilice Notepad++, por el momento solo nos interesa ver que tipo de archivo es apoyandonos en la informacion de la cabecera del archivo, obteniendo esto:

Rar!

Mas claro ni el agua, podemos ver que se trata de un archivo comprimido, renombramos el archivo con extencion .rar, descomprimimos y
obtenemos dos archivos mas:

1.- hell.mp3
2.- naranjito.jpg

En el archivo "hell.mp3" esta oculta nuestra clave para poder pasar el reto, esto lo hacemos con el software "mp3Stego", pero tenemos que tener otra clave para poder ver el contenido que nos arroge el mp3stego de dicho archivo.

La clave que buscamos se encuentra en "naranjito.png", por mi parte utilice un editor de imagenes llamado "Paint Shop Pro", el cual nos permitira separar canales como:

:arrow: RGB
:arrow: HSL y
:arrow: CMYK

Despues de separar los canales nos encontramos que al separar el canal HSL en la parte de saturacion y matiz se observa claramente la clave en la parte superior izquierda.
La clave es: kaos

Ahora que ya tenemos la primer clave procedemos a utilizar mp3Stego, esto es lo mas sencillo, lo hacemos de esta manera desde la linea de comandos (OJO, el archivo hell.mp3 tendra que estar en el directorio en donde se encuentra el ejecutable Decode.exe, o bien lo pueden agregar al path de windoze para tener disponible el comando):

Z:\MP3Stego\Decode -X hell.mp3

Despues de esto nos pide una clave, que es la que hemos obtenido de "naranjito.jpg", la escribimos en minusculas y esto nos genera dos archivos, entre ellos figura uno en formato "txt" ahi es en donde tenemos la clave.

La clave final es: chihuahua

Y LISTO !!!, ese es todo el procedimiento para poder pasar el reto.

Agradesco la ayuda de HaDeS asi como tambien por poder publicar mi solucion y darme un espacio en su blog XD.

ATTE: kmykc
>>EOF


Solución oficial alternativa


La explicación está "mas clara que el agua", igualmente para aclarar dudas (Si es que las hay), publico mi solución con imágenes para dinamizar un poco la publicación.

La primera parte no hace falta explicarla mucho, en resumen, extraemos el bit menos significativo de la imagen, teniendo en cuenta que la estamos recorriendo por columnas, y no por filas como normalmente se haría. teniendo en cuenta que la estamos recorriendo por filas (Por cada fila se recorre cada columna)

Luego de agrupar todos los bits menos significativos podemos convertirlos a carácteres, como claramente lo escribió kmykc. Después de convertirlos lo llevamos a un archivo.
Mi script para resolver ésta parte del reto es el siguiente:

<?php
// @titulo: Script solucionador reto #3 primera parte
// @autor: http://www.sinfocol.org
//Creamos la imagen
$img = imagecreatefrompng('stego.png');
//Obtenemos las dimensiones
$dim = getimagesize('stego.png');
//Declaramos un valor vacpio para $chr
$chr = '';
//Recorremos las filas
for($i=0;$i<$dim[1];$i++){
  //Por cada fila recorrida recorremos sus columnas
  for($j=0;$j<$dim[0];$j++){
    //Obtenemos el color que se encuentra en la posición (i,j)
    $rgb  = imagecolorat($img,$j,$i);
    //Extraemos el bit menos significativo, primero convirtiendo a hexadecimal los valores respectivos
    $t[0] = substr(base_convert(($rgb >> 16) & 255,10,2),-1); //r
    $t[1] = substr(base_convert(($rgb >> 8) & 255,10,2),-1); //g
    $t[2] = substr(base_convert($rgb & 255,10,2),-1); //b
    //Concatenamos los bits obtenidos
    $chr .= $t[0].$t[1].$t[2];
  }
}
//Imprimimos el resultado
echo bin2asc($chr);

//Función proporcionada por http://snarkles.net/scripts/sneak/sneak.php
function bin2asc($str) {
  $str = explode("\r\n", chunk_split($str, 8));
  $ns = '';
  for ($n = 0; $n < count($str) - 1; $n++) {
    $ns .= chr(base_convert($str[$n], 2, 10));
  }
  return $ns;
}
?>

La forma de utilizar este script es por medio de la línea de comandos, de la siguiente forma

c:\php -f script.php > resultado.hex

De forma que el PHP al ejecutar la función "echo", inmediatamente el resultado se lleva al archivo resultado.hex

Abrimos nuestro archivo con un editor hexadecimal y observamos la cabecera .rar

Procedemos a renombrar el archivo, y al extraer el contenido encontramos a naranjito y hell.mp3.
Abrimos a naranjito con irfanview, y presionamos varias veces shift + u para auto ajustar los colores, queda algo así:

No necesariamente tenemos que usar un programa externo para poder resolver esta parte, también pudimos haber utilizado el script solucionador del primer reto con unos leves cambios

<?php
// @titulo: Script solucionador reto #3 segunda parte
// @autor: http://www.sinfocol.org
$img = imagecreatefrompng('naranjito.png'); //Creamos la imagen apartir del archivo
$medida = getimagesize('naranjito.png'); //Obtenemos el tamaño de la imagen
$x=$medida[0];
$y=$medida[1];
$nueva = imagecreate($x,$y); //Creamos una nueva imagen que almacenará las diferencias
$f='';
for($i=0;$i<$x;$i++){
  for($j=0;$j<$y;$j++){
    $color = Loc($img,$i,$j);
    //Si el color es blanco ponemos un pixel blanco
    if($color[0]==255 && $color[1]==255 && $color[2]==255){
      $f = imagecolorresolve($nueva,255,255,255);
      imagesetpixel($nueva,$i,$j,$f);
    }else{
      //Si es diferente ponemos un pixel negro
      $f = imagecolorresolve($nueva,0,0,0);
      imagesetpixel($nueva,$i,$j,$f);    
    }
  }
}
//Mostramos la imagen con las diferencias
header('Content-Type: image/png');
imagepng($nueva);
//Función para retornar el color rojo, verde y azul de un pixel de una imagen
function Loc($img,$x,$y){
  $rgb = imagecolorat($img,$x,$y);
 $t[0] = ($rgb >> 16) & 255;
 $t[1] = ($rgb >> 8) & 255;
 $t[2] = $rgb & 255;
 return $t;
}
?>

Donde el resultado es la siguiente imagen, y se puede observar claramente la palabra "kaos" en la esquina superior izquierda:

Luego hacemos lo que nos indicó kmykc en su tutorial, y ejecutamos el comando anteriormente visto (Para extraer el contenido final)

Es todo!
Hay una versión alternativa de solucionar la primera parte, y es un software en Visual Basic 6 programado por paipai. Pueden descargar los códigos fuentes de el ocultador y desocultador de archivos en imágenes, de AcÁ!
De nuevo felicitaciones a kmykc, quien es el primero en realizar uno de mis retos, sigue adelante!

Archivado en: Esteganografía, Retos informáticos |

8 comentarios

  1. kmykc Marzo 17, 2009 @ 12:49 pm

    De perlas tu solucion brother, tendre que ponerme a estudiar mucho mas para no tener que depender de software externo XD.

    Salu2...

  2. Trancek Marzo 17, 2009 @ 3:47 pm

    Buenas solucioens ;), un dia de estos me animo a tus retos puto jeje que de estegano me quede loco en blindsec por un tiempo.

  3. Sysroot Marzo 17, 2009 @ 8:21 pm

    Claro, anímate, creo que seguiré poniendo retos de estegano para hacer que esta web tenga contenido valioso del tema, sin olvidar claro está, el tema global de la seguridad informática.

  4. paipai Marzo 24, 2009 @ 2:49 pm

    felicidades a ambos , crei que nunca lo resolveria nadie
    cicklow no lo publico en su web y ya ni me acordaba del reto ese

  5. Sysroot Marzo 24, 2009 @ 3:01 pm

    Gracias pai, estamos tratando de hacer aportes significativos a la esteganografía.

  6. flowrd21 Octubre 22, 2009 @ 1:42 pm

    habre la cabeza, pues he visto tus otros "retos", je..me soprende q tengas tiempo para crearlos...a mi me gustaría hacer un crack me con mi propia encriptación justo ahora :p..
    pero me tengo q dedicar a arreglar sitios con SQL injection, pues digo: ¡por qué todavía sigue habiendo sitios con estos problemas si ya existe la filosofía de una nueva buena red gracias a la web 2.0!??para mí el programador con quien estoy tratand está enamorado...:$

  7. Sysroot Octubre 22, 2009 @ 5:53 pm

    Hola de nuevo Flowrd21, tiempo tengo a veces muy poco, ya ni duermo casi, pero con tal de comunicar lo que sé hago lo que sea!, con lo de la encriptación pues adelante, y si quieres la puedes mandar para publicarla acá a ver quien se anima a romper el crackme.
    Yo también estoy enamorado!, pero de la vida :$, aunque ahora estoy buscando novias, creo que te deberías postular, cumples con todos los requisitos :$

  8. flowrd21 Octubre 25, 2009 @ 7:58 am

    jaja!... :P
    umm...
    comparto la verdad de q yo tampoco duermo una m*** y tengo q tomar litros de café y energizantes para vivir, pues como programadora esto es muy común de vivir como zombies, porq de noche nos concentramos más...
    así q cumplo con todos los requisitos???!!
    Para sorpresa tuya puedes ver q uso GNU/LInuX..
    saludos q encuentres a esa cracker q tanto buscás..
    si quieres agrégame a tu msn...
    :p saluds

Deja un comentario