Внедрение SQL, в зависимости от типа используемой СУБД и условий внедрения, может дать возможность атакующему выполнить произвольный запрос к базе данных (например, прочитать содержимое любых таблиц, удалить, изменить или добавить данные), получить возможность чтения и/или записи локальных файлов и выполнения произвольных команд на атакуемом сервере.
Существует миф, что SQL Injection возможна только в Web-приложениях, но, к несчастью для ВСЕХ разработчиков, внедрение произвольного кода возможно в любом приложении где используется СУБД (так же любая).
В этой статье я хочу показать, что от внедрения SQL-кода не застрахован никто, в тои числе и профессиональные разработчики, пишушие крупные промышленные системы, которые успешно используются на предприятиях. В качестве “жертвы” выступит крупная система документооборота DocsVision 3.6. Опишу суть SQL Injection в DV: допустим у нас официально куплено N-лицензий этой системы документооборота, но мы решили увеличить кол-во этих лицензий путём внедрения своего произвольного кода. Изначально может показаться, что задача практически нерешаемая, так как это комерческий продукт и наверняка разработчики уделили достаточно много времени для его защиты, но…
Запускаем SQL Server Profiler и анализируем все запросы, которые генерит приложение DocsVision, особое внимание уделяем коду, который отсылает приложение при каждом новом подключении пользователя.
И вот, что удалось “поймать”:
1.SELECT COUNT(*) FROM2.(SELECT DISTINCT [UserID], [ComputerName] FROM [dbo].[dvsys_sessions]) t0Смотрим DDL-скрипт этой таблицы:
01.CREATE TABLE [dbo].[dvsys_sessions](02. [SessionID] [uniqueidentifier] ROWGUIDCOL NOT NULL,03. [UserID] [uniqueidentifier] NULL,04. [LocaleID] [int] NOT NULL,05. [LoginTime] [datetime] NOT NULL,06. [LastAccessTime] [datetime] NOT NULL,07. [ComputerName] [varchar](32) NULL,08. CONSTRAINT [PK_dvsys_sessions] PRIMARY KEY CLUSTERED09.(10. [SessionID] ASC11.)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]12.) ON [PRIMARY]13. 14.GO01.CREATE TABLE [dbo].[dvsys_sessions](02. [SessionID] [uniqueidentifier] ROWGUIDCOL NOT NULL,03. [UserID] [uniqueidentifier] NULL,04. [LocaleID] [int] NOT NULL,05. [LoginTime] [datetime] NOT NULL,06. [LastAccessTime] [datetime] NOT NULL,07. [ComputerName] [varchar](32) NULL,08. [UserID2] [uniqueidentifier] NULL,09. [ComputerName2] [varchar](32) NULL,10. CONSTRAINT [PK_dvsys_sessions] PRIMARY KEY CLUSTERED11.(12. [SessionID] ASC13.)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]14.) ON [PRIMARY]15. 16.GO01.CREATE TRIGGER [dbo].[FuckOffConnections] ON [dbo].[dvsys_sessions]02.FOR INSERT03.AS04.Update t105.set06.UserID=null,07.ComputerName=null,08.UserID2=t2.UserID,09.ComputerName2=t2.ComputerName10.From dvsys_sessions t1 inner join inserted t2 on t1.SessionID=t2.SessionIDНо на этом наше SQL-внедрение не закончено, ведь на эту таблицу могут ссылаться другие объекты базы данных, что может привести к сбою в работе. Для поиска всех объектов, которые ссылаются на таблицу [dbo].[dvsys_sessions], выполним запрос:
1.select distinct OBJECT_NAME(id) obj2.from sys.sysdepends3.where depid=OBJECT_ID('dbo.dvsys_sessions')В результате мы получили 4 объекта:
1.dvsys_log_write_message2.dvsys_session_get_info3.dvsys_session_list4.FuckOffConnectionsНа деле изменения затронули всего 3 объекта, причём всего пару строк:
dvsys_log_write_message
001.ALTER PROCEDURE [dbo].[dvsys_log_write_message] (002. @UserID AS uniqueidentifier,003. @SessionID AS uniqueidentifier,004. @Type AS int,005. @Operation As int,006. @Code AS int,007. @TypeID AS uniqueidentifier = NULL,008. @ResourceID AS uniqueidentifier = NULL,009. @ParentID AS uniqueidentifier = NULL,010. @NewResourceID AS uniqueidentifier = NULL,011. @ResourceName As nvarchar(512) = NULL,012. @Data AS ntext = NULL013. )014.AS015.BEGIN016. SET NOCOUNT ON017. DECLARE @ComputerName AS varchar(32)018. DECLARE @InternalData AS varchar(128)019. SELECT @InternalData = NULL020. 021. -- Retrieve ComputerName022. --Оригинальный код023. --SELECT @ComputerName = [ComputerName]024. --FROM [dbo].[dvsys_sessions] WITH(NOLOCK)025. --WHERE [SessionID] = @SessionID026. 027. --Код, который мы внедрили:028. SELECT @ComputerName = [ComputerName2]029. FROM [dbo].[dvsys_sessions] WITH(NOLOCK)030. WHERE [SessionID] = @SessionID031. 032. -- Retrieve LoginTime for Logout operation033. IF @Operation = 2034. BEGIN035. SELECT @InternalData = CONVERT(varchar(128), [LoginTime], 20)036. FROM [dbo].[dvsys_sessions] WITH(NOLOCK)037. WHERE [SessionID] = @SessionID038. END ELSE039. -- Get Card description and Card type ID040. IF (@Operation >= 3 AND @Operation <= 7) OR @Operation = 20041. BEGIN042. SELECT @ResourceName = [Description], @TypeID = CardTypeID043. FROM [dbo].[dvview_instances] WITH(NOLOCK)044. WHERE InstanceID = @ResourceID045. END ELSE046. -- Get Card description, Card type ID and topic name047. IF @Operation = 27048. BEGIN049. SELECT @ResourceName = [Description], @TypeID = CardTypeID, @InternalData = [Topic]050. FROM [dbo].[dvview_instances] WITH(NOLOCK)051. WHERE InstanceID = @ResourceID052. END ELSE053. -- Get InstanceID and description of Card that has row with specified ResourceID in section with specified TypeID054. IF (@Operation >= 8 AND @Operation <= 12) OR @Operation = 13 OR @Operation = 19055. BEGIN056. IF @ParentID IS NULL057. BEGIN058. DECLARE @GetRowParentID AS nvarchar(256)059. SELECT @GetRowParentID = N'SELECT @ParentID = [InstanceID] FROM [dvtable_{' + CONVERT(nvarchar(36), @TypeID) +060. N'}] WITH(NOLOCK) WHERE [RowID] = ''{' + CONVERT(nvarchar(36), @ResourceID) + N'}'''061. 062. EXECUTE [dbo].[sp_executesql] @GetRowParentID, N'@ParentID uniqueidentifier OUTPUT', @ParentID OUTPUT063. END064. 065. SELECT @ResourceName = [Description]066. FROM [dbo].[dvview_instances] WITH(NOLOCK)067. WHERE InstanceID = @ParentID068. END ELSE069. -- Get File name070. IF ((@Operation >= 14) AND (@Operation <= 18)) OR (@Operation = 21) OR (@Operation = 24) OR (@Operation = 25)071. BEGIN072. SELECT @ResourceName = [Name]073. FROM [dbo].[dvview_files] WITH(NOLOCK)074. WHERE FileID = @ResourceID075. 076. -- Get Destination File name077. IF (@Operation = 25)078. BEGIN079. SELECT @InternalData = [Name]080. FROM [dbo].[dvview_files] WITH(NOLOCK)081. WHERE FileID = @ParentID082. END083. END ELSE084. -- Get Card description085. IF @Operation = 19086. BEGIN087. SELECT @ResourceName = [Description]088. FROM [dbo].[dvview_instances] WITH(NOLOCK)089. WHERE InstanceID = @ParentID090. END ELSE091. -- Get Report alias092. IF @Operation = 23093. BEGIN094. SELECT @ResourceName = [Alias]095. FROM [dbo].[dvsys_reports] WITH(NOLOCK)096. WHERE ID = @ResourceID097. END ELSE098. -- Get Card Type alias099. IF @Operation = 26100. BEGIN101. SELECT @ResourceName = [Alias]102. FROM [dbo].[dvsys_carddefs] WITH(NOLOCK)103. WHERE CardTypeID = @ResourceID104. END105. 106. INSERT [dbo].[dvsys_log] WITH(ROWLOCK) (UserID, ComputerName, [Date], Type, Operation, Code, TypeID, ResourceID, ParentID, ResourceName, NewResourceID, Data)107. VALUES(@UserID, @ComputerName, GETDATE(), @Type, @Operation, @Code, @TypeID, @ResourceID, @ParentID, @ResourceName, @NewResourceID, ISNULL(@Data, @InternalData))108.END01.ALTER PROCEDURE [dbo].[dvsys_session_get_info] (02. @SessionID AS uniqueidentifier03. )04.AS05.BEGIN06.--Оригинальный код07.-- SELECT t0.UserID, LocaleID, AccountName, ISNULL(ComputerName, '')08.-- FROM [dbo].[dvsys_sessions] t0 WITH(NOLOCK)09.-- JOIN [dbo].[dvsys_users] t1 WITH(NOLOCK) ON t0.UserID = t1.UserID10.-- WHERE (SessionID = @SessionID)11. 12.--Внедрённый код13. SELECT t0.UserID2 as UserID, LocaleID, AccountName, ISNULL(ComputerName2, '')14. FROM [dbo].[dvsys_sessions] t0 WITH(NOLOCK)15. JOIN [dbo].[dvsys_users] t1 WITH(NOLOCK) ON t0.UserID2 = t1.UserID16. WHERE (SessionID = @SessionID)17.END01.ALTER PROCEDURE [dbo].[dvsys_session_list]02.AS03.BEGIN04. 05.--Оригинальный код06.-- SELECT SessionID, AccountName, LoginTime, LastAccessTime, ComputerName07.-- FROM [dbo].[dvsys_sessions] t0 WITH(NOLOCK)08.-- JOIN [dbo].[dvsys_users] t1 WITH(NOLOCK) ON t0.UserID = t1.UserID09.-- ORDER BY AccountName ASC, LoginTime DESC10. 11.--Внедрённый код12. SELECT SessionID, AccountName, LoginTime, LastAccessTime, ComputerName2 as ComputerName13. FROM [dbo].[dvsys_sessions] t0 WITH(NOLOCK)14. JOIN [dbo].[dvsys_users] t1 WITH(NOLOCK) ON t0.UserID2 = t1.UserID15. ORDER BY AccountName ASC, LoginTime DESC16.END
No comments:
Post a Comment