(转载)穿透Session 0 隔离(二)

作者:freethy 发布于:2012-7-30 13:47 Monday

上一篇我们已经对Session 0 隔离有了进一步认识,如果在开发过程中确实需要服务与桌面用户进行交互,可以通过远程桌面服务的API 绕过Session 0 的隔离完成交互操作。

对于简单的交互,服务可以通过WTSSendMessage 函数,在用户Session 上显示消息窗口。对于一些复杂的UI 交互,必须调用CreateProcessAsUser 或其他方法(WCF、.NET远程处理等)进行跨Session 通信,在桌面用户上创建一个应用程序界面。

WTSSendMessage 函数

如果服务只是简单的向桌面用户Session 发送消息窗口,则可以使用WTSSendMessage 函数实现。首先,在上一篇下载的代码中加入一个Interop.cs 类,并在类中加入如下代码:

public static IntPtr WTS_CURRENT_SERVER_HANDLE = IntPtr.Zero;

public static void ShowMessageBox(string message, string title)
{
    int resp = 0;
    WTSSendMessage(
        WTS_CURRENT_SERVER_HANDLE,
        WTSGetActiveConsoleSessionId(),
        title, title.Length,
        message, message.Length,
        0, 0, out resp, false);
}

[DllImport("kernel32.dll", SetLastError = true)]
public static extern int WTSGetActiveConsoleSessionId();

[DllImport("wtsapi32.dll", SetLastError = true)]
public static extern bool WTSSendMessage(
    IntPtr hServer,
    int SessionId,
    String pTitle,
    int TitleLength,
    String pMessage,
    int MessageLength,
    int Style,
    int Timeout,
    out int pResponse,
    bool bWait);

在ShowMessageBox 函数中调用了WTSSendMessage 来发送信息窗口,这样我们就可以在Service 的OnStart 函数中使用,打开Service1.cs 加入下面代码:

protected override void OnStart(string[] args)
{
    Interop.ShowMessageBox("This a message from AlertService.",
                           "AlertService Message");
}

编译程序后在服务管理器中重新启动AlertService 服务,从下图中可以看到消息窗口是在当前用户桌面显示的,而不是Session 0 中。

services

CreateProcessAsUser 函数

如果想通过服务向桌面用户Session 创建一个复杂UI 程序界面,则需要使用CreateProcessAsUser 函数为用户创建一个新进程用来运行相应的程序。打开Interop 类继续添加下面代码:

public static void CreateProcess(string app, string path)
{
    bool result;
    IntPtr hToken = WindowsIdentity.GetCurrent().Token;
    IntPtr hDupedToken = IntPtr.Zero;

    PROCESS_INFORMATION pi = new PROCESS_INFORMATION();
    SECURITY_ATTRIBUTES sa = new SECURITY_ATTRIBUTES();
    sa.Length = Marshal.SizeOf(sa);

    STARTUPINFO si = new STARTUPINFO();
    si.cb = Marshal.SizeOf(si);

    int dwSessionID = WTSGetActiveConsoleSessionId();
    result = WTSQueryUserToken(dwSessionID, out hToken);

    if (!result)
    {
        ShowMessageBox("WTSQueryUserToken failed", "AlertService Message");
    }

    result = DuplicateTokenEx(
          hToken,
          GENERIC_ALL_ACCESS,
          ref sa,
          (int)SECURITY_IMPERSONATION_LEVEL.SecurityIdentification,
          (int)TOKEN_TYPE.TokenPrimary,
          ref hDupedToken
       );

    if (!result)
    {
        ShowMessageBox("DuplicateTokenEx failed" ,"AlertService Message");
    }

    IntPtr lpEnvironment = IntPtr.Zero;
    result = CreateEnvironmentBlock(out lpEnvironment, hDupedToken, false);

    if (!result)
    {
        ShowMessageBox("CreateEnvironmentBlock failed", "AlertService Message");
    }

    result = CreateProcessAsUser(
                         hDupedToken,
                         app,
                         String.Empty,
                         ref sa, ref sa,
                         false, 0, IntPtr.Zero,
                         path, ref si, ref pi);

    if (!result)
    {
        int error = Marshal.GetLastWin32Error();
        string message = String.Format("CreateProcessAsUser Error: {0}", error);
        ShowMessageBox(message, "AlertService Message");
    }

    if (pi.hProcess != IntPtr.Zero)
        CloseHandle(pi.hProcess);
    if (pi.hThread != IntPtr.Zero)
        CloseHandle(pi.hThread);
    if (hDupedToken != IntPtr.Zero)
        CloseHandle(hDupedToken);
}

[StructLayout(LayoutKind.Sequential)]
public struct STARTUPINFO
{
    public Int32 cb;
    public string lpReserved;
    public string lpDesktop;
    public string lpTitle;
    public Int32 dwX;
    public Int32 dwY;
    public Int32 dwXSize;
    public Int32 dwXCountChars;
    public Int32 dwYCountChars;
    public Int32 dwFillAttribute;
    public Int32 dwFlags;
    public Int16 wShowWindow;
    public Int16 cbReserved2;
    public IntPtr lpReserved2;
    public IntPtr hStdInput;
    public IntPtr hStdOutput;
    public IntPtr hStdError;
}

[StructLayout(LayoutKind.Sequential)]
public struct PROCESS_INFORMATION
{
    public IntPtr hProcess;
    public IntPtr hThread;
    public Int32 dwProcessID;
    public Int32 dwThreadID;
}

[StructLayout(LayoutKind.Sequential)]
public struct SECURITY_ATTRIBUTES
{
    public Int32 Length;
    public IntPtr lpSecurityDescriptor;
    public bool bInheritHandle;
}

public enum SECURITY_IMPERSONATION_LEVEL
{
    SecurityAnonymous,
    SecurityIdentification,
    SecurityImpersonation,
    SecurityDelegation
}

public enum TOKEN_TYPE
{
    TokenPrimary = 1,
    TokenImpersonation
}

public const int GENERIC_ALL_ACCESS = 0x10000000;

[DllImport("kernel32.dll", SetLastError = true,
    CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
public static extern bool CloseHandle(IntPtr handle);

[DllImport("advapi32.dll", SetLastError = true,
    CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
public static extern bool CreateProcessAsUser(
    IntPtr hToken,
    string lpApplicationName,
    string lpCommandLine,
    ref SECURITY_ATTRIBUTES lpProcessAttributes,
    ref SECURITY_ATTRIBUTES lpThreadAttributes,
    bool bInheritHandle,
    Int32 dwCreationFlags,
    IntPtr lpEnvrionment,
    string lpCurrentDirectory,
    ref STARTUPINFO lpStartupInfo,
    ref PROCESS_INFORMATION lpProcessInformation);

[DllImport("advapi32.dll", SetLastError = true)]
public static extern bool DuplicateTokenEx(
    IntPtr hExistingToken,
    Int32 dwDesiredAccess,
    ref SECURITY_ATTRIBUTES lpThreadAttributes,
    Int32 ImpersonationLevel,
    Int32 dwTokenType,
    ref IntPtr phNewToken);

[DllImport("wtsapi32.dll", SetLastError=true)]
public static extern bool WTSQueryUserToken(
    Int32 sessionId,
    out IntPtr Token);

[DllImport("userenv.dll", SetLastError = true)]
static extern bool CreateEnvironmentBlock(
    out IntPtr lpEnvironment,
    IntPtr hToken,
    bool bInherit);

在CreateProcess 函数中同时也涉及到DuplicateTokenEx、WTSQueryUserToken、CreateEnvironmentBlock 函数的使用,有兴趣的朋友可通过MSDN 进行学习。完成CreateProcess 函数创建后,就可以真正的通过它来调用应用程序了,回到Service1.cs 修改一下OnStart 我们来打开一个CMD 窗口。如下代码:

protected override void OnStart(string[] args)
{
    Interop.CreateProcess("cmd.exe",@"C:\Windows\System32\");
}

重新编译程序,启动AlertService 服务便可看到下图界面。至此,我们已经可以通过一些简单的方法对Session 0 隔离问题进行解决。大家也可以通过WCF 等技术完成一些更复杂的跨Session 通信方式,实现在Windows 7 及Vista 系统中服务与桌面用户的交互操作。

cmd

参考资料

1. WTSSendMessage Function
http://msdn.microsoft.com/en-us/library/aa383842(VS.85).aspx

2. CreateProcessAsUser Function
http://msdn.microsoft.com/en-us/library/ms682429(v=VS.85).aspx

3. WTSSendMessage (wtsapi32)
http://www.pinvoke.net/default.aspx/wtsapi32/WTSSendMessage.html

4. WTSQueryUserToken Function
http://msdn.microsoft.com/en-us/library/aa383840(VS.85).aspx

5. http://www.pinvoke.net/

评论(18) 引用(0) 浏览(4130)

(转载)穿透Session 0 隔离(一)

作者:freethy 发布于:2012-7-30 13:33 Monday

服务(Service)对于大家来说一定不会陌生,它是Windows 操作系统重要的组成部分。我们可以把服务想像成一种特殊的应用程序,它随系统的“开启~关闭”而“开始~停止”其工作内容,在这期间无需任何用户参与。

Windows 服务在后台执行着各种各样任务,支持着我们日常的桌面操作。有时候可能需要服务与用户进行信息或界面交互操作,这种方式在XP 时代是没有问题的,但自从Vista 开始你会发现这种方式似乎已不起作用。

Session 0 隔离实验

下面来做一个名叫AlertService 的服务,它的作用就是向用户发出一个提示对话框,我们看看这个服务在Windows 7 中会发生什么情况。

using System.ServiceProcess;
using System.Windows.Forms;

namespace AlertService
{
    public partial class Service1 : ServiceBase
    {
        public Service1()
        {
            InitializeComponent();
        }

        protected override void OnStart(string[] args)
        {
            MessageBox.Show("A message from AlertService.");
        }

        protected override void OnStop()
        {
        }
    }
}

程序编译后通过Installutil 将其加载到系统服务中:

service

在服务属性中勾选“Allow service to interact with desktop” ,这样可以使AlertService 与桌面用户进行交互。

property

在服务管理器中将AlertService 服务“启动”,这时任务栏中会闪动一个图标:

点击该图标会显示下面窗口,提示有个程序(AlertService)正在试图显示信息,是否需要浏览该信息:

flashmeg

尝试点击“View the message”,便会显示下图界面(其实这个界面我已经不能从当前桌面操作截图了,是通过Virtual PC 截屏的,其原因请继续阅读)。注意观察可以发现下图的桌面背景已经不是Windows 7 默认的桌面背景了,说明AlertService 与桌面系统的Session 并不相同,这就是Session 0 隔离作用的结果。

alertsession

Session 0 隔离原理

在Windows XP、Windows Server 2003 或早期Windows 系统时代,当第一个用户登录系统后服务和应用程序是在同一个Session 中运行的。这就是Session 0 如下图所示:

oldsession

但是这种运行方式提高了系统安全风险,因为服务是通过提升了用户权限运行的,而应用程序往往是那些不具备管理员身份的普通用户运行的,其中的危险显而易见。

从Vista 开始Session 0 中只包含系统服务,其他应用程序则通过分离的Session 运行,将服务与应用程序隔离提高系统的安全性。如下图所示:

newsession

这样使得Session 0 与其他Session 之间无法进行交互,不能通过服务向桌面用户弹出信息窗口、UI 窗口等信息。这也就是为什么刚才我说那个图已经不能通过当前桌面进行截图了。

image_3F7C7630_8523daf7-557d-4afb-ab70-a755a54e3296

Session 检查

在实际开发过程中,可以通过Process Explorer 检查服务或程序处于哪个Session,会不会遇到Session 0 隔离问题。我们在Services 中找到之前加载的AlertService 服务,右键属性查看其Session 状态。

pe

可看到AlertService 处于Session 0 中:

pep

再来看看Outlook 应用程序:

outlookpe

很明显在Windows 7 中服务和应用程序是处于不同的Session,它们之间加隔了一个保护墙,在下篇文章中将介绍如何穿过这堵保护墙使服务与桌面用户进行交互操作。

作者写的图文并茂,深入浅出,极品好文

from:http://www.cnblogs.com/gnielee/archive/2010/04/07/session0-isolation-part1.html

评论(62) 引用(0) 浏览(2957)

IE6789,FF之间Css Hack整理

作者:freethy 发布于:2012-7-23 13:33 Monday

非转载,亲自整理,亲测。

代码如下,注意顺序不能乱。

 

div{
    color:gray;       /*FF等非IE浏览器字体色将为灰色    ff */
    color:red\0;     /*IE8 IE9字体色将为红色    ie8 */
    color:yellow\9\0;     /*IE9字体色将为黄色    ie9 */
    *color:green;     /*IE7字体色将为绿色    ie7 */
    _color:blue;     /*IE6字体色将为蓝色    ie6 */
}


评论(9) 引用(0) 浏览(2155)

MSSQL2005在networkservice权限运行附加数据库报(Microsoft SQL Server,错误: 5120)

作者:freethy 发布于:2012-7-11 13:33 Wednesday

附加数据库出错:

无法打开物理文件 "XXXXXXXXXXXXX"。操作系统错误 5:"5(拒绝访问。)"。 (Microsoft SQL Server,错误: 5120)

解决方法:目录(即文件夹)权限不够,将SQLServer2005MSSQLUser$计算机名$MSSQLSERVER用户组加入,改为完全控制,注意一定要是完全控制才可以.

评论(16) 引用(0) 浏览(2004)

IDC加强asp.net 1.1/2.0安全性一篇技巧

作者:freethy 发布于:2012-7-11 13:32 Wednesday

IDC加强asp.net 1.1/2.0安全性一篇技巧

ASP.NET 1.1:

打开 C:\WINDOWS\Microsoft.NET\Framework\v1.1.4322\CONFIG\machine.config

设置:
< location allowOverride="false">

< identity impersonate="true" userName="" password=""/>

ASP.NET 2.0 以上:
C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\CONFIG\web.config

设置:
< identity impersonate="true"/>

如果没有此两项,分别进行增加:

< location allowOverride="true">  改为:< location allowOverride="false">
        < system.web>
            < securityPolicy>
                < trustLevel name="Full" policyFile="internal"/>
                < trustLevel name="High" policyFile="web_hightrust.config"/>
                < trustLevel name="Medium" policyFile="web_mediumtrust.config"/>
                < trustLevel name="Low" policyFile="web_lowtrust.config"/>
                < trustLevel name="Minimal" policyFile="web_minimaltrust.config"/>
            < /securityPolicy>
        < trust level="Full" originUrl=""/>
        < identity impersonate="true"/>  < !--  这里增加 -->
        < /system.web>
    < /location>

评论(31) 引用(0) 浏览(2275)

防止aspxspy木马列服务,iis信息,执行命令提权等操作

作者:freethy 发布于:2012-7-1 13:32 Sunday

环境:windows2003+iis6+.net2.0

处于安全考虑,对服务器安全进行设置。上传aspxspy测试。

ASPXSPY探针

1.禁止aspxspy木马执行命令提权 和读取注册表

测试方法一:

    先打开:C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\config\web.config
    之后找到
    <trust level="Full" originUrl="" />
    改为
    <trust level="High" originUrl="" />
    然后打开C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\config\web_hightrust.config
    里面有一句:
    <SecurityClass Name="RegistryPermission" Description="System.Security.Permissions.RegistryPermission, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"/>
    把这句删掉,就可以防止读取注册表
经测试,执行以上操作后网站oledb权限没了,导致access数据库无法访问。
测试方法二:
%SystemRoot%/ServicePackFiles/i386/activeds.dll
%SystemRoot%/system32/activeds.dll
%SystemRoot%/system32/activeds.tlb
搜索这两个文件,把USER组和POWERS组去掉,只保留administrators和system权限

经过测试,重启后导致3389,80,1433等端口无法远程连接。害得我联系机房人员才解决问题.

 

方法三(未测试):
禁止C:\WINDOWS\system32\inetsrv目录下的adsiis.dll的user权限可以禁止遍历IIS
但是列出服务器详细信息和所有进程没办法解决!

据说产生副作用:和装有sqlserver冲突,导致无法远程连接服务器(此问题未测试,个人感觉应该是mssql没设好的原因)
方法四:
<system.web>
<identity impersonate="true" />
</system.web>
将以上代码复制到C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\CONFIG\web.config
此方法经过测试可以有效防止 【执行命令】 列出【系统信息】【用户信息】【服务】.
转载注明出处:http://www.freethy.cn/?p=481
<完>

评论(11) 引用(0) 浏览(2256)

Powered by emlog 苏ICP备11068260号-3