Nov 7, 2009

System Center Roadmap


SQL Server Version Numbers


This morning I have been building out a new ConfigMgr demo environment on my laptop based on Server 2008 R2. I had already installed SQL 2008, but couldn’t remember if I had installed SP1 for SQL 2008 or not. I looked at the version number, but then had to go to Microsoft to find out what the version number equated to in terms of SP level. For future reference to myself and others, here is a concise list of SQL Server version numbers and the corresponding friendly name. This will be useful if you already know the version number. If you need to know how to get the version number from you SQL server, refer to this page (which is where this list of numbers came from). That page lists the SQL queries for each version to perform to obtain the version number.

SQL Version
Version Number
SQL Server 2008 RTM
2007.100.1600.0
SQL Server 2008 SP1
2007.100.2531.0
SQL Server 2005 RTM
2005.90.1399
SQL Server 2005 SP1
2005.90.2047
SQL Server 2005 SP2
2005.90.3042
SQL Server 2005 SP3
2005.90.4035
SQL Server 2000 RTM
2000.80.194.0
SQL Server 2000 SP1
2000.80.384.0
SQL Server 2000 SP2
2000.80.534.0
SQL Server 2000 SP3
2000.80.760.0
SQL Server 2000 SP3a
2000.80.760.0
SQL Server 2000 SP4
2000.8.00.2039
SQL Server 7.0 RTM
7.00.623
SQL Server 7.0 SP1
7.00.699
SQL Server 7.0 SP2
7.00.842
SQL Server 7.0 SP3
7.00.961
SQL Server 7.0 SP4
7.00.1063
SQL Server 6.5 RTM
6.50.201
SQL Server 6.5 SP1
6.50.213
SQL Server 6.5 SP2
6.50.240
SQL Server 6.5 SP3
6.50.258
SQL Server 6.5 SP4
6.50.281
SQL Server 6.5 SP5
6.50.415
SQL Server 6.5 SP5a
6.50.416
SQL Server 6.5 SP5a Update
6.50.479

Nov 4, 2009

Интеграция драйверов в образ windows 5.х версий

Покопался в нёдрах ОС и нашел для себя способ подсовывания драйверов новых в уже "установленную" копию операционки.
Жаль, без переподписывания "правильным" сертификатом layout.inf файлика совсем красиво это не удалось сделать (файл драйверов дублируется в двух местах). Если править layout.inf файл то все драйвера "встроенные" в windows из дистрибутива станут автоматически неподписанными из-за чего появится много "сексуальных" моментов при работе с устройствами...


Для меня в любом случае есть некоторые непонятные пока моменты которые я не смог разрешить, изучаю на предмет проблем всё-равно т.к. возможно что и drvindex.inf файл тоже является хитрым и после его модификации чтото может отвалиться.

Вся операция заключена в нескольких шагах:

1. создаю каталог куда кладу драйвер.
2. дальше создаю файл ответов для makecab примерно такого содержимого (в моем случае).
 Называю его drv.ddf
.OPTION EXPLICIT
.Set CabinetNameTemplate=intel_net.CAB
.Set Cabinet=on
.Set Compress=on
e1000325.din
E1000325.sys
e1000msg.dll
NicCo.dll
NicEtCo.dll
NicEtCoE.dll
NicInst.dll
NicInstE.dll
PROUnstl.exe

3. запускаю makecab /f drv.ddf В конце получив архив intel_net.cab
4. кладу CAB два раза в образ по адресам \Driver Cache\i386 и \Driver Cache
5. открываю notepad с файлом \inf\drvindex.inf В нём надо вписать ссылку на

CAB с перечислением находящихся там файлов. Делается это так (в моем случае):
В секции [Version]
находим параметр CabFiles=
добавляем туда наш. Она станет CabFiles=SP3,driver,intel_net
Дальше спускаемся на пару строк и создаем секцию [intel_net] в ней перечисляем все файлы в

нашем CABе.(аналогично как перечислял в файле ответов список файлов)
Теперь идем в самый конец файла и в секции [Cabs] добавляем ссылочку на наш новый.
intel_net=intel_net.cab

6. все inf файлы из драйвера копируем в \Windows\inf каталог.
7. всё сохраняю и перезагружаю машину. Проходя стадию определения устройств, Windows

Mini-setup будет "из коробки" понимать сетевые адаптеры в inf файлах.

Oct 30, 2009

SQL Injection в DocsVision 3.6


Внедрение SQL-кода (англ. SQL injection) — один из распространённых способов взлома сайтов и программ, работающих с базами данных, основанный на внедрении в запрос произвольного SQL-кода.
Внедрение SQL, в зависимости от типа используемой СУБД и условий внедрения, может дать возможность атакующему выполнить произвольный запрос к базе данных (например, прочитать содержимое любых таблиц, удалить, изменить или добавить данные), получить возможность чтения и/или записи локальных файлов и выполнения произвольных команд на атакуемом сервере.

Существует миф, что SQL Injection возможна только в Web-приложениях, но, к несчастью для ВСЕХ разработчиков, внедрение произвольного кода возможно в любом приложении где используется СУБД (так же любая).
В этой статье я хочу показать, что от внедрения SQL-кода не застрахован никто, в тои числе и профессиональные разработчики, пишушие крупные промышленные системы, которые успешно используются на предприятиях. В качестве “жертвы” выступит крупная система документооборота DocsVision 3.6. Опишу суть SQL Injection в DV: допустим у нас официально куплено N-лицензий этой системы документооборота, но мы решили увеличить кол-во этих лицензий путём внедрения своего произвольного кода. Изначально может показаться, что задача практически нерешаемая, так как это комерческий продукт и наверняка разработчики уделили достаточно много времени для его защиты, но…

Запускаем SQL Server Profiler и анализируем все запросы, которые генерит приложение DocsVision, особое внимание уделяем коду, который отсылает приложение при каждом новом подключении пользователя.
И вот, что удалось “поймать”:
1.SELECT COUNT(*) FROM
2.(SELECT DISTINCT [UserID], [ComputerName] FROM [dbo].[dvsys_sessions]) t0
Где [UserID] – идентификатор пользователя, а [ComputerName] – рабочая станция, с которой идёт подключение. Не трудно сделать вывод, что приложение считает кол-во уникальных подключений [UserID]+[ComputerName]. Теперь мы знаем какие значения отслеживает приложение, но, не имея исходного кода, мы не можем поменять текст запроса, который зашит внутри кода, НО мы можем изменить объект к которому идёт обращение, а именно таблицу, которая хранит информацию об этих подключениях: [dbo].[dvsys_sessions].

Смотрим 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 CLUSTERED
09.(
10.    [SessionID] ASC
11.)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.GO

Ну и сразу же возникает идея: обнулять (NULL) поля [UserID] и [ComputerName], но значения всё-таки нужны и просто удалить мы их не можем, для того, чтобы обмануть приложение, создадим в этой таблице 2 наших поля [UserID2] и [ComputerName2], в которые будем дублировать значения из полей [UserID] и [ComputerName], а их сами очищать с помощью DML-триггера. Тогда 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.    [UserID2] [uniqueidentifier] NULL,
09.    [ComputerName2] [varchar](32) NULL,
10. CONSTRAINT [PK_dvsys_sessions] PRIMARY KEY CLUSTERED
11.(
12.    [SessionID] ASC
13.)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.GO

А код триггера, который и будет выполнять всю “грязную” работу:

01.CREATE TRIGGER [dbo].[FuckOffConnections] ON [dbo].[dvsys_sessions]
02.FOR INSERT
03.AS
04.Update t1
05.set
06.UserID=null,
07.ComputerName=null,
08.UserID2=t2.UserID,
09.ComputerName2=t2.ComputerName
10.From dvsys_sessions t1 inner join inserted t2 on t1.SessionID=t2.SessionID

Всё, что делает этот триггер-это дублирует записи в наши внедрённые поля, очищая первоисточник. Таким образом, не зависимо от кол-ва подключений к DocsVision, на запрос зашитий в системе всегда будет возвращать одну запись, т.е. система ВСЕГДА будет думать, что используется только одна лицензия.
Но на этом наше SQL-внедрение не закончено, ведь на эту таблицу могут ссылаться другие объекты базы данных, что может привести к сбою в работе. Для поиска всех объектов, которые ссылаются на таблицу [dbo].[dvsys_sessions], выполним запрос:

1.select distinct OBJECT_NAME(id) obj
2.from sys.sysdepends
3.where depid=OBJECT_ID('dbo.dvsys_sessions')
В результате мы получили 4 объекта:
1.dvsys_log_write_message
2.dvsys_session_get_info
3.dvsys_session_list
4.FuckOffConnections

т.к. FuckOffConnections-это наш триггер, то нам достаточно поправить всего 3 объекта (dvsys_log_write_message, dvsys_session_get_info, dvsys_session_list).
На деле изменения затронули всего 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 = NULL
013.    )
014.AS
015.BEGIN
016.    SET NOCOUNT ON
017.    DECLARE @ComputerName AS varchar(32)
018.    DECLARE @InternalData AS varchar(128)
019.    SELECT @InternalData = NULL
020. 
021.    -- Retrieve ComputerName
022.    --Оригинальный код
023.    --SELECT @ComputerName = [ComputerName]
024.    --FROM [dbo].[dvsys_sessions] WITH(NOLOCK)
025.    --WHERE [SessionID] = @SessionID
026. 
027.    --Код, который мы внедрили:
028.    SELECT @ComputerName = [ComputerName2]
029.    FROM [dbo].[dvsys_sessions] WITH(NOLOCK)
030.    WHERE [SessionID] = @SessionID
031. 
032.    -- Retrieve LoginTime for Logout operation
033.    IF @Operation = 2
034.    BEGIN
035.        SELECT @InternalData = CONVERT(varchar(128), [LoginTime], 20)
036.        FROM [dbo].[dvsys_sessions] WITH(NOLOCK)
037.        WHERE [SessionID] = @SessionID
038.    END ELSE
039.    -- Get Card description and Card type ID
040.    IF (@Operation >= 3 AND @Operation <= 7) OR @Operation = 20
041.    BEGIN
042.        SELECT @ResourceName = [Description], @TypeID = CardTypeID
043.        FROM [dbo].[dvview_instances] WITH(NOLOCK)
044.        WHERE InstanceID = @ResourceID
045.    END ELSE
046.    -- Get Card description, Card type ID and topic name
047.    IF @Operation = 27
048.    BEGIN
049.        SELECT @ResourceName = [Description], @TypeID = CardTypeID, @InternalData = [Topic]
050.        FROM [dbo].[dvview_instances] WITH(NOLOCK)
051.        WHERE InstanceID = @ResourceID
052.    END ELSE
053.    -- Get InstanceID and description of Card that has row with specified ResourceID in section with specified TypeID
054.    IF (@Operation >= 8 AND @Operation <= 12) OR @Operation = 13 OR @Operation = 19
055.    BEGIN
056.        IF @ParentID IS NULL
057.        BEGIN
058.            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 OUTPUT
063.        END
064. 
065.        SELECT @ResourceName = [Description]
066.        FROM [dbo].[dvview_instances] WITH(NOLOCK)
067.        WHERE InstanceID = @ParentID
068.    END ELSE
069.    -- Get File name
070.    IF ((@Operation >= 14) AND (@Operation <= 18)) OR (@Operation = 21) OR (@Operation = 24) OR (@Operation = 25)
071.    BEGIN
072.        SELECT @ResourceName = [Name]
073.        FROM [dbo].[dvview_files] WITH(NOLOCK)
074.        WHERE FileID = @ResourceID
075. 
076.        -- Get Destination File name
077.        IF (@Operation = 25)
078.        BEGIN
079.            SELECT @InternalData = [Name]
080.            FROM [dbo].[dvview_files] WITH(NOLOCK)
081.            WHERE FileID = @ParentID
082.        END
083.    END ELSE
084.    -- Get Card description
085.    IF @Operation = 19
086.    BEGIN
087.        SELECT @ResourceName = [Description]
088.        FROM [dbo].[dvview_instances] WITH(NOLOCK)
089.        WHERE InstanceID = @ParentID
090.    END ELSE
091.    -- Get Report alias
092.    IF @Operation = 23
093.    BEGIN
094.        SELECT @ResourceName = [Alias]
095.        FROM [dbo].[dvsys_reports] WITH(NOLOCK)
096.        WHERE ID = @ResourceID
097.    END ELSE
098.    -- Get Card Type alias
099.    IF @Operation = 26
100.    BEGIN
101.        SELECT @ResourceName = [Alias]
102.        FROM [dbo].[dvsys_carddefs] WITH(NOLOCK)
103.        WHERE CardTypeID = @ResourceID
104.    END
105. 
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.END

dvsys_session_get_info
01.ALTER PROCEDURE [dbo].[dvsys_session_get_info] (
02.    @SessionID AS uniqueidentifier
03.    )
04.AS
05.BEGIN
06.--Оригинальный код
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.UserID
10.--  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.UserID
16.    WHERE (SessionID = @SessionID)
17.END

dvsys_session_list
01.ALTER PROCEDURE [dbo].[dvsys_session_list]
02.AS
03.BEGIN
04. 
05.--Оригинальный код
06.--  SELECT SessionID, AccountName, LoginTime, LastAccessTime, ComputerName
07.--  FROM [dbo].[dvsys_sessions] t0 WITH(NOLOCK)
08.--  JOIN [dbo].[dvsys_users] t1 WITH(NOLOCK) ON t0.UserID = t1.UserID
09.--  ORDER BY AccountName ASC, LoginTime DESC
10. 
11.--Внедрённый код
12.    SELECT SessionID, AccountName, LoginTime, LastAccessTime, ComputerName2 as ComputerName
13.    FROM [dbo].[dvsys_sessions] t0 WITH(NOLOCK)
14.    JOIN [dbo].[dvsys_users] t1 WITH(NOLOCK) ON t0.UserID2 = t1.UserID
15.    ORDER BY AccountName ASC, LoginTime DESC
16.END
Вот и всё, за какие-то 30-40 минут, путём внедрения своего SQL-кода, мы увеличили кол-во лицензий до бесконечности (при этом совсем не затронув само приложение и не утратив его полную работоспособность).

Domain Join Account – Minimum Rights

This falls under another one of those items that I have had in my private notes for a while, but can’t remember where I found it. When setting up the account in a ConfigMgr Task Sequence to join the new computer account to the domain, you must give that account rights in order for it to work. It is essentially a service account, so it should only be given the bare minimum rights. What are those rights? You can “Delegate Control” on the OU to the account and only give it “Allow” for the following:

Permission
Apply To
Reset Password
Computer Objects
Validated write to DNS host name
Computer Objects
Validated write to service principal name
Computer Objects
Read/Write Account Restrictions
Computer Objects
Create/Delete Computer Objects
This object and all descendant objects
Hopefully this will help others…and it will make it easier for me to quickly locate the next time I need to set it!

Set SPN for SQL 2005 (SCCM Remote SQL Fix)

I have found many references to issues with a remote SQL server running under a service account around the Internet. This issue only manifests itself if the SMS provider is located on the site server and the SQL server is located remotely running as a service and is running under standard privileges. The most common symptoms are errors in the installation log related to smsrprt.mof and anonymous login; posted here is a great description (http://www.eggheadcafe.com/software/aspnet/30654425/sccm-mixedmode-setup-fai.aspx)
So, here is the problem. If you are running SQL under a standard user service account as you would in a cluster or remote SQL instance the SPN must be registered with the FQDN and it must be registered both with and without the port number. There is a great description of how to do this here: http://msdn2.microsoft.com/en-us/library/ms189585.aspx; but it is related to IIS. I will give you the short version.

Method 1: The “Right” way
  1. Install the Windows 2003 support tools somewhere on a machine in the domain
  2. Login as a Domain Admin
  3. Run  setspn -A MSSQLSvc/ Note YOU MUST USE THE FQDN
  4. Run  setspn -A MSSQLSvc/:   Note YOU MUST USE THE FQDN, and the most common port is 1443
  5. Run setspn -L validate that “servicePrincipalName:” has been set like you expect
  6. Restart the SQL server after AD replication has completed
  7. Run the following query on the SQL server; this MUST return KERBEROS:
    select auth_scheme from sys.dm_exec_connections where session_id=@@spid
Method 2: The “easy” way
In adsiedit grant the service account the ability to write the servicePrincipalName to “SELF”
Taken from: http://support.microsoft.com/kb/319723

    1. Click Start, click Run, type Adsiedit.msc, and then click OK.

    2. In the ADSI Edit snap-in, expand Domain [DomainName], expand DC= RootDomainName, expand CN=Users, right-click CN= AccountName , and then click Properties.
      • DomainName is a placeholder for the name of the domain. 
      • RootDomainName is a placeholder for the name of the root domain. 
      • AccountName is a placeholder for the account that you specify to start the SQL Server service. 
      • If you specify the Local System account to start the SQL Server service, AccountName is a placeholder for the account that you use to log on to Microsoft Windows. 
      • If you specify a domain user account to start the SQL Server service, AccountName is a placeholder for the domain user account. 

    3. In the CN= AccountName Properties dialog box, click the Security tab.
    4. On the Security tab, click Advanced. 
    5. In the Advanced Security Settings dialog box, make sure that SELF is listed under Permission entries.
      • If SELF is not listed, click Add, and then add SELF.

    6. Under Permission entries, click SELF, and then click Edit.
    7. In the Permission Entry dialog box, click the Properties tab. 
    8. On the Properties tab, click This object only in the Apply onto list, and then click to select the check boxes for the following permissions under Permissions:
      • Read servicePrincipalName 
      • Write servicePrincipalName

    9. Click OK two times.

I would love to reference all the posts and blogs and KB’s that I used to come to this but I wouldn’t know where to begin. I would also like to thank my good friend Prabhu Padhi on the SMS team for fielding my call last night and offering his assistance.
Originally posted here by me: http://www.myitforum.com/forums/m_164437/mpage_1/key_/tm.htm#164437

Oct 21, 2009

Запуск команд от имени системы

Часто по роду работы возникает необходимость запустить ту или иную команду от имени компьютера. В основном это необходимо для тестовых целей, но иногда таким образом можно “спасти жизнь” операционной системе.

Способ прост, как и все гениальное. Мы используем утилиту sc

sc create Console binpath= "c:\windows\system32\cmd.exe /k start" type= own type= interact
Обращаю ваше внимание на то, что пробелы после знака равно обязательны.
В Windows Vista и Windows 7 вы получите предупреждение о том, что отображение программы может быть некорректным, не обращайте внимания.
net start Сonsole
При запуске новой службы сразу появляется следующее диалоговое окно:
warnsess
Выбираем view the message и вуаля:
whoami
Если служба больше не понадобиться – можно удалить ее командой
sc delete Console