CLR via Windbg – string vs securestring

Ayer en el Octoberconference organizado por el grupo de usuarios de Málaga tuve la oportunidad de dar una charla de depuración en entornos de producción. Es una sesión muy especial que me trae muy gratos recuerdos de mi trabajo en soporte de Microsoft.

Durante la sesión vemos la importancia de la minuciosidad ante un problema en un entorno de producción, captura de volcados de memoria, análisis básico win32 y análisis en .NET.

Los asistentes siempre se sorprenden de la facilidad con la que se puede obtener los valores de las variables (passwords, strings de conexión, requests en asp.net…) en memoria. Unos 10 minutos antes de empezar, Unai Zorrilla me sugirió que hiciésemos una demo con SecureString para que se viese la utilidad de esa clase.

A si que vamos a por ello…

Partimos de este código

 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Security;

namespace ConsoleApplication1
{
  class Program
   {
     static void Main(string[] args)
     {
       using (SecureString ss = new SecureString())
       {
           string noss = string.Empty;
           while (true)
           {
             ConsoleKeyInfo cki = Console.ReadKey();
             if (cki.Key == ConsoleKey.Enter) break;
             ss.AppendChar(cki.KeyChar);
             noss += cki.KeyChar.ToString();
           }
          Console.WriteLine(“secure:”+ss);
          Console.WriteLine(“No secure:”+noss);
          Console.ReadLine();
       } 

     }
 }
}

Ejecutamos la aplicación e introducimos algo de texto pulsando enter, vemos los resultados de los Console.WriteLine…y nos quedamos ahi, no damos al segundo enter que si no perdemos la ejecución

Y ahora abrimos nuestro entorno de depuración de volcados favorito, el windbg 🙂

Pulsamos F6 y seleccionamos el proceso de la aplicación

Según nos adjuntamos al ejecutable, pasamos a cargar la extensión SOS en memoria. Esta hará posible que depuremos aplicaciones .NET desde WinDBG de forma muy sencilla.

.loadby sos mscorwks

Y ahora estamos preparados para investigar la memoria del proceso. Vamos a listar los objetos manejados de los stacks de los diferentes threads (~ = thread,  *=todos, e=ejecutar, !dumpstackobjects = mostrar objetos .net del stack del thread en curso)

~*e !dumpstackobjects

Si cotilleamos un poco la salida encontraremos estos valores (las direcciones hex pueden cambiar)

0580ebdc 0168981c System.String prueba prueba
0580ebe0 01683984 System.Security.SecureString

Son las referencias a los objetos que estamos buscando. Si volcamos el System.String, vemos la siguiente estructura

0:010> !do 0168981c
Name: System.String
MethodTable: 790fcb30
EEClass: 790fca90
Size: 44(0x2c) bytes
GC Generation: 0
(C:WindowsassemblyGAC_32mscorlib2.0.0.0__b77a5c561934e089mscorlib.dll)
String: prueba prueba  –> juas que chivato, no? reconoce el string y me lo muestra tal cual 🙂
Fields:
MT Field Offset Type VT Attr Value Name
791018e0 4000096 4 System.Int32 0 instance 14 m_arrayLength
791018e0 4000097 8 System.Int32 0 instance 13 m_stringLength
790fe534 4000098 c System.Char 0 instance 70 m_firstChar
790fcb30 4000099 10 System.String 0 shared static Empty
>> Domain:Value 00374ea8:790d81bc <<
7912b1d8 400009a 14 System.Char[] 0 shared static WhitespaceChars

Si no nos lo mostrase tal cual, en negroesta resaltado lo que parece ser la dirección de comienzo del string que contiene la memoria (dir base de la clase string + 0x0c). De modo que vamos a volcarla directamente a ver que vemos.

0:010> du 0168981c +0x0c
01689828 “prueba prueba”

Demasiado fácil 😛 Vamos a volcar ahora el secure string a ver que es lo que vemos…

0:010> !do 01683984
Name: System.Security.SecureString
MethodTable: 791915e4
EEClass: 792316d8
Size: 20(0x14) bytes
GC Generation: 0  //mhhh ya no se chiva :/
(C:WindowsassemblyGAC_32mscorlib2.0.0.0__b77a5c561934e089mscorlib.dll)
Fields:
MT Field Offset Type VT Attr Value Name
791916a0 4001e6e 4 …ty.SafeBSTRHandle 0 instance 01689700 m_buffer
791018e0 4001e6f 8 System.Int32 0 instance 13 m_length
79107584 4001e70 c System.Boolean 0 instance 0 m_readOnly
79107584 4001e71 d System.Boolean 0 instance 1 m_enrypted
79107584 4001e72 b00 System.Boolean 0 shared static supportedOnCurrentPlatform
>> Domain:Value 00374ea8:1 <<

Véis que en este caso no hay nada que cante ni ninguna dirección de donde se pueda rascar, quizás tenga que ver con que SecureString fue el resultado de una petición del gobierno de USA para proteger cierta información en memoria, por eso no se deja ver el contenido 🙂

Gracias por la idea Unai! (y a los asistentes por aguantarme)

Happy Hacking!

 

PD ->  .detach para liberar el proceso 😛

Publicado por

10 comentarios en “CLR via Windbg – string vs securestring”

  1. David … impresionante … ahora bien, para cuando un manualcito de configuracion ? donde explicar como configurar el “server” de simbolos para poder depurar y otros truquillos para poder hacerle la vida mas facil (o dificil) a los developers …
    de nuevo … esta serie de post son los que me alegran el dia 😀

    Saludos

  2. Muy bien, David. Ayer creo que faltó tiempo; una hora y cuarto no son suficientes para contar bien esto de la depuración, pero seguramente valieron para despertar la curiosidad de más de uno. [:)]

  3. La idea de nada vale si no hay alguien que la ponga en práctica y la enseñe tan bien como tu!!

    Abrazos…

    Cuando volvemos por Fuenjirola???? Seguro que te estás moriendo de ganas 🙂

  4. La idea de nada vale si no hay alguien que la ponga en práctica y la enseñe tan bien como tu!!

    Abrazos…

    Cuando volvemos por Fuenjirola???? Seguro que te estás muriendo de ganas 🙂

  5. La idea de nada vale si no hay alguien que la ponga en práctica y la enseñe tan bien como tu!!

    Abrazos…

    Cuando volvemos por Fuenjirola???? Seguro que te estás muriendo de ganas 🙂

  6. Me parece muy bueno el ejemplo.
    Ahora he hecho algunas pruebas con strings, en vez de utilizar un SecureString cambio el string a un Char[], correo el Windbg y con sólo eso no se puede obtener la información del string.

    public void MyFunction () {
    String vSecureInfo = “MyPassword”;
    Char[] vSecureChar = vSecureInfo.ToCharArray();
    vSecureInfo = null;
    }

    Con este código, detengo la ejecución justo de pués de vSecureInfo = null, ejecuto el WinDbg para obtener el stack, y ya no aparece el contenido de vSecureInfo y el de vSecureChar.

    Hay alguna manera de revisar la memoria para obtener la información que quiero proteger?, es que el SecureString me parece muy bueno, pero estoy viendo el escenario real en donde lo utilizaría.

    Gracias.

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *