内容


利用远程注册表访问

跟踪多台机器能提高效率并降低易受攻击

Comments

在一个软件开发测试环境中,跟踪机器被证明是非常困难的,尤其是当机器的数量达到两位数的时候。在哪台机器上使用了什么软件?使用的 NT 是什么版本?服务包(service pack)的级别是什么?安装了什么修订程序?您可以走到每台机器前手工检查核对所有这些问题,但是当机器分散在一个广阔的区域内,这样做会是一个非常费时的过程。

在这样的情形下,如果有一种方法,能够不必实际使用某台机器并且不安装额外软件,就可以获取那台机器的信息,那将是很有用的。然后,收集到的信息可以用来分配资源和识别那些可能易受恶意的用户和程序攻击的机器。本文描述了利用远程注册表访问的某些方面。

警告:通过使用本文中描述的远程注册表功能,您能节省系统管理的大量时间。但是仍要小心,因为编辑另一个系统的注册表会与编辑您自己的注册表一样危险(如果不比编辑您自己的更危险的话)。

利用安装功能

在这里的 WebSphere Business Integrator(WSBI)测试环境中,我们有大约 40 台测试机器,它们的地理位置分散在整个英国 Hursley 实验室中。在最初的测试阶段期间,我们的注意力主要集中于 WSBI 的安装和配置。在测试机器上不断地安装和重新安装各种产品以及服务包和必备软件 ― 通常必须重新安装整个操作系统。很快,我们发现要监视每台测试机器状态几乎是不可能的。我们需要一种方法,它可以在不必访问每台机器的情况下,快速知道该机器所处的状态。

在 WSBI 安装中,我们要在单一安装封装器中安装并配置了大约 15 个 IBM 产品 ― 例如 DB2 V7.2、MQSeries V5.2、HTTP Server V1.3.12。正如对于所有好的安装程序,在任何安装开始之前,都要检查目标机器以确保它满足要安装的软件的前提条件 ― 例如服务包级别和相关产品。这个检查通常在 InstallShield 脚本中由编写注册表脚本检查相关值来完成的。

例如,一种最常见的检查就是验证 NT 服务包级别。 图 1 说明了键 HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion 下的注册表项,它们会出现在 Regedit.exe 中。

图 1. 显示在 Regedit 中的注册表值
显示在 Regedit 中的注册表值
显示在 Regedit 中的注册表值

当在脚本中查询一个注册表项时,需要知道三样东西:

  • 要查询的键名称 ― 本例中,是 HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion
  • 键中值的名称,这里是“CSDVersion”
  • 正在查询的值类型,这里是一个字符串值

使用 InstallShield 脚本函数 RegDBGetKeyValueEx 来执行注册表查询。但是假设您想要检查安装了什么级别的服务包。 清单 1显示可以如何达到这一点。

清单 1. 抽取服务包级别
STRING szKey, szName, svServicePackVersion;
NUMBER nvType, nvSize;
begin
    svKey = "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion";
    svName = "CSDVersion";
    nvType = REGDB_STRING;
    RegDBGetKeyValueEx (szKey, szName, nvType, svServicePackVersion, nvSize);
end;

清单 1 将返回值“Service Pack 6”并把它存储在 svServicePackVersion 中。然后,您可以知道这台机器上安装了 Service Pack 6。通过执行类似这样的各种查询,可能确定一台机器的配置以及在它上面安装了什么软件。

当我们意识到可以对远程机器的注册表执行这些查询时,我们的实验室工作取得了突破性的进展。

连接到远程注册表

要通过脚本访问远程机器上的注册表,需要远程机器上的管理员特权。我们发现当运行我们的脚本时,拥有在远程机器上具有管理员特权的一个用户帐户并使用这个用户名和密码登录到脚本正在运行的这台机器是一个难题。 图 2说明了这个过程。

假设在我们的 WSBI 测试环境中,有三台测试机器,使用第四台作为审计机器。在每台测试机器上,我们都需要添加一个用户帐户并赋予它管理员特权;我们将用户名命名为“auditor”并赋予它密码“angelus”。这是每台机器上需要手工执行的唯一操作。每台测试机器上的这些帐户现在都允许我们通过审计机器上运行的脚本来访问每台机器的注册表。

图 2. 每台机器上放置的审计帐户
每台机器上放置的审计帐户
每台机器上放置的审计帐户

现在假设我们用刚才创建的帐户(用户名“auditor”,密码“angelus”)登录到 AuditMachine。下一步是重新运行 清单 1 上的脚本,但是这次不检查本地注册表,而是想知道机器“Gunn”的服务包级别,所以我们需要连接到它的注册表上。要做到这一点,我们使用命令 RegDBConnectRegistry 。这个功能创建到远程注册表的连接。要连接到 Gunn,该命令类似于:

RegDBConnectRegistry ("Gunn" , HKEY_LOCAL_MACHINE, 0 );

把它放置在脚本中,那么我们就得到:

清单 2. 远程抽取机器 Gunn 的服务包级别
begin
    RegDBConnectRegistry ("Gunn" , HKEY_LOCAL_MACHINE, 0 );
    svKey = "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion";
    svName = "CSDVersion";
    nvType = REGDB_STRING;

    RegDBGetKeyValueEx (szKey, szName, nvType, svServicePackVersion, nvSize);
end;

如果一切顺利的话,我们现在就能访问 Gunn 的注册表并抽取服务包级别。

接下来,通过在 RegBConnectRegistry 命令中用表示其它两台机器的相应的名称替代“Gunn”,然后运行相同的过程;我们就可以抽取这两台机器的服务包级别。

我们注意到,三次重复输入相同的代码效率很低,因此可以使用循环机制来轮流查询每台机器的注册表。需要输入的全部信息是每台机器的名称。这可以通过创建一个文本文件来完成,该文件中,每一行包含一个机器的名称。因此,假设我们已经创建了一个名为 machineList.txt 的文本文件,其中输入了我们希望查询的三台机器的名称,并将它保存在 C 盘的根目录下。现在我们可以进一步修改脚本以把这些机器名读取到一个列表结构中,并轮流连接到每台机器的注册表。

清单 3. 从多台机器中抽取服务包级别
begin
    listMachines = ListCreate(STRINGLIST);
    ListReadFromFile (listMachines, "c:\\machineList.txt");
    nResult = ListGetFirstString (listMachines, svMachineName);
    while (nResult != END_OF_LIST)
    RegDBConnectRegistry (svMachineName , HKEY_LOCAL_MACHINE, 0 );
    svKey = "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion";
    svName = "CurrentVersion";
    nvType = REGDB_STRING;
    RegDBGetKeyValueEx (svKey, svName, nvType, svServicePackVersion, nvSize);
    nResult = ListGetNextString (listMachines, svMachineName);
    endwhile;
end;

以上代码将从 machineList.txt 文件中读入一个机器名,连接到它的注册表,进行查询,然后继续移到在文本文件中命名的下一台机器。使用这种方法的优点是通过简单编辑 machineList.txt 文件中的名称,我们能非常容易地在审计过程中添加和除去机器。

输出信息

到现在为止,您可能已经注意到当我们执行这些查询时,还没有产生任何输出。所以,现在我们来讨论确定表示输出结果的最好方法。我们团队决定把输出格式化为 XML 文件,因为这样使我们可以浏览检索到的信息,并且允许我们可能开发的任何其它应用程序利用这些数据。 清单 4显示了用适当命名的标记生成的 XML 文件。

清单 4. 从多台机器中抽取服务包级别并输出到 XML 文件
begin
    CreateFile (nvFileHandle, "C:\", "Audit.xml");
    WriteLine(nvFileHandle, "<?xml version="1.0"?>");
    WriteLine(nvFileHandle, "<audits>");
    listMachines = ListCreate(STRINGLIST);
    ListReadFromFile (listMachines, "c:\machineList.txt");
    nResult = ListGetFirstString (listMachines, svMachineName);
    
while (nResult != END_OF_LIST)
    RegDBConnectRegistry (svMachineName , HKEY_LOCAL_MACHINE, 0 );
    svKey = "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion";
    svName = "CurrentVersion";
    nvType = REGDB_STRING;
    RegDBGetKeyValueEx (svKey, svName, nvType, svServicePackVersion, nvSize);
    WriteLine(nvFileHandle, "<MachineName>");
    WriteLine(nvFileHandle, "<ServicePack>" + svCSDVersion+ "</ServicePack>"
    WriteLine(nvFileHandle, "</MachineName>");
    nResult = ListGetNextString (listMachines, svMachineName);
endwhile;
    
WriteLine(nvFileHandle, "</audits>");
CloseFile(nvFileHandle)
end;

如果我们在 AuditMachine 上运行 清单 4(假设我们使 machineList.txt 包含我们的目标机器的名称),并且我们的审计帐户设置正确,那么我们将生成一个名为 Audit.xml 的输出文件。然后,我们可以浏览这个文件并查看每台机器上的服务包级别是什么(请参阅 图 3)。

图 3. 审计运行的 XML 输出示例
审计运行的 XML 输出示例
审计运行的 XML 输出示例

在我们的示例中,通过从三台机器中抽取单段信息,我们执行了一个很小的审计。理论上,以这种方式能从多少台机器抽取信息或者抽取多少信息并没有限制。在这里的 WSBI 测试中,目前我们每次审计大约 40 台机器。使用这里描述的技术,我们当前的审计系统能确定:

  • 机器运行的是 NT 还是 2000
  • 是否应用了服务包
  • 安装了什么修订程序
  • 是否安装了 Norton Anti-Virus
  • 安装了哪些 IBM 产品以及是什么级别

对于每次审计,涉及的原理与我们示例中的完全相同:

  • 读入机器名或者 IP 地址的列表
  • 轮流连接到每台机器的远程注册表
  • 从每台机器的注册表中抽取信息

这里显示了对一台机器进行完整审计的示例。

收集在 XML 文件的单一资源库中的这些信息让我们极其清晰地了解了我们的测试环境,并且使我们可以更有效地管理硬件资源。

进一步扩展原理

到目前为止,我们只查询了远程机器的注册表。但是,它并不仅限于查询。还有可能 编辑远程机器的注册表。

回到我们的示例,假设那些机器位于三个不同的房间 ― Gunn 在“The War Room”、Wesley 在“The Test Cell”、Cordelia 在“Room 101”。如果我们可以引入使 XML 文件中包含机器位置的一些方法,那么这会使我们的审计方便些。一种解决方案是在注册表中放置一个额外键表示机器的位置。使用 regedit.exe,在键 HKEY_LOCAL_MACHINE\SOFTWARE\IBM\MachineLocation 下,我们创建了一个名为“location”的新字符串值,如 图 4

图 4. 在 regedit.exe 中创建位置注册表键
在 regedit.exe 中创建位置注册表键
在 regedit.exe 中创建位置注册表键

但是如果有很多机器的话,那么遍历每台机器并且手工创建每个位置键就不很理想了。比较好的方法是将值远程地插入到每台机器中。执行的方法与检索注册表值的方法是完全相同的。首先,连接到远程注册表:

   RegDBConnectRegistry ("Gunn" , HKEY_LOCAL_MACHINE, 0 );

接着,设置注册表值:

     svKey = "SOFTWARE\\IBM\\MachineLocation";
      svName = "Location";
      nvType = REGDB_STRING;
   svLocation = "The War Room"

最后,执行注册表操作。这次,我们使用 RegDBSetKeyValueEx ,它设置注册表值(正如它的名字所表示的)。

       RegDBSetKeyValueEx (svKey, svName, nvType, svLocation, nvSize);

然后,审计过程就可以查询这个键了。也可以用这种方法更新甚至删除注册表键,虽然从远程注册表删除键是非常危险的。

优点

这种方法的审计的主要优点是:

  • 它除去了在测试机器上安装任何第三方软件的需求,因此也除去了由此产生的潜在干扰;需要做的全部操作就是在每台机器上创建一个用户帐户。
  • 可以通过在脚本中修改那些您想要查询的注册表键以及要审计的机器,非常容易地调整您的审计过程。
  • 这个审计过程不会以任何方式干扰正在被审计的机器上执行的操作。那台机器的用户完全不知道审计的发生。5 秒内就可生成本文前面包含的完整的审计 XML 文件。

提高安全性

恶意的用户

要弄坏一台机器,没有比通过对注册表胡乱更改里面的内容更好的方法了,因此恶意的用户远程地访问您的注册表将会是一大灾难。然而,由于我们之前设置的远程-注册表帐户是管理员用户,所以我们只要通过执行以下这些步骤,就能将远程注册表访问权限限制为管理员。

  1. 运行 Regedt32.exe。
  2. 打开以下注册表键: HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\SecurePipeServers\WinReg
  3. 单击 WinReg 键,然后在“安全(Security)”下拉菜单中选择“权限(Permissions)”。
  4. 确保在框中只出现具有完全控制的管理员。
  5. 要完全限制所有的远程-注册表访问,从框中除去所有名称。

恶意的程序:识别易受攻击的机器

恶意的程序进入系统的主要方法是利用操作系统的安全性漏洞。我们都知道近期“红色代码(Code Red)”和类似的病毒已经引出了许多问题。堵住这些漏洞的补丁程序通常在那些利用漏洞的病毒猖獗运行之前的几个月就可获得,但是在一个多机器的环境中,您如何能识别哪些机器易受攻击呢?补丁程序或者修订程序的安装总是在注册表中留下痕迹。打开 Regedit 并浏览到键 HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Hotfix ,列出了当前已安装的所有修订程序。例如,防止“红色代码”病毒的补丁程序称为 Q300972。在一台安装了这个修订的机器上,在上面显示的键下,会有一个称为 Q300972 的键。因此,利用这里所描述的技术,通过在审计期间查找这个键,我们能识别没有安装补丁程序的任何机器,并且相应地对它们进行处理。

反病毒软件是任何安全性实现的一个必需部分,但是有些机器可能没有安装反病毒软件,或者软件可能过时了,从而使它们门户大开易受攻击。远程注册表调用可以用来找到这些机器。

安装任何一种反病毒软件都会在注册表中留下一些踪迹,假设在我们的系统上,在安装了反病毒软件后,它在注册表中留下了下列踪迹:

HKEY_LOCAL_MACHINE\SOFTWARE\IBM\VirusKiller 
StringValue "Version"  Value "2.2"
StringValue "LastUpdated" Value "25/12/2001"

然后,审计可以寻找这些值以便识别那些没有安装反病毒软件或者杀毒软件需要更新的机器。

如果您查看前面提供的审计示例,就会注意到执行了两个这种性质的检查。我们的审计检查了“红色代码”修订是否存在,检查了反病毒软件并且抽取出它的版本。

结束语

本文描述了在小心正确地使用远程注册表访问时,它是如何成为一个有价值的工具,用来抽取有关多台机器的信息以及识别易受攻击的机器。您可以使用本文中的示例作为创建您自己的相关变体的一个起点。通过使用它和包含的源代码,您应该发现在您自己的环境中实现远程注册表工具是非常简单的。


相关主题


评论

添加或订阅评论,请先登录注册

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=10
Zone=Open source
ArticleID=20799
ArticleTitle=利用远程注册表访问
publish-date=01012002