背景知识:Win32消息系统视窗系统的应用程序完全是通过消息来控制的。当一个按键被按下时,一个消息就发送到了当前的活动窗口以便告知某个键被按下。当视窗系统认为某个应用软件需要重绘他自己的区域,系统就会发送一个消息给软件。实际上每个应用程序需要知晓的事件发生后,都会有一个消息发送给这个应用程序。这些消息存放在一个队列里,并且被应用程序顺序执行。这就需要有一个非常可信的机构来管理应用程序,然而在Win32下,消息机构是有缺陷的。在某个窗口下的任意一个应用程序都可以发送消息给同一桌面的其他任意程序,也就是说没有一个专门的机构来认证消息的来源,不考虑接收窗口是否属于发送方的程序,也不考虑接收方是否希望得到这样的消息。我们无法区分一个由恶意程序发出的消息和Windows内核发出的消息。本文下面的内容就是讲如何利用这个缺少消息认证的缺陷来进行攻击,并且提出了可以利用特定的消息篡改窗口和相应的进程。
概述在下面将提到的例子中,我使用了运行在Windows2000 professional版的Network Associates VirusScan v4.5.1。 VirusScan是以LocalSystem身份执行的,我以guest用户登陆目标是骗取VirusScan执行我的代码以便实现权限的提升。通过下面几个简单的步骤就可以完成该任务:1. 在VirusScan中找到一个合适的窗口(文本框最为合适),并且获取该窗口的句柄。2. 解除文本框可能出现的长度限制,以便输入大量的数据。3. 粘入二进制代码。4. 强制VirusScan以LocalSystem身份执行输入的命令。做到上面几个步骤非常的容易,视窗系统提供了所有我们需要的函数。我写了一个名叫Shatter的小程序来实现这些功能。除此之外还需要一个16进制编辑器(我选用了Ultraedit)和一个调试器(我选用了Windbg)。需要特别注意:某些病毒扫描器会警告Shatter的zip包中的sploit.bin带有”Win32/Beavuh”病毒。这些扫描器正确地发现该文件打开了一个shell并且将shell连接到了网络。通常情况下这样做是恶意的,扫描器正确的报告了这个行为。文件中带有的代码确实属于恶意代码,但是病毒扫描器将它定义为病毒确是错误的。一个Windows消息是由一个标识符和两个参数这样的三部分构成的。参数根据不同的消息而定。这样我们就只需要关心四点:一个接受消息的窗口的句柄,一个消息,两个参数。下面我们来看看具体的执行步骤:第一步:寻找一个合适的窗口我们需要找到一个文本框来输入相应的内容。不必担心输入内容的限制,后面的步骤中将解决这个问题。打开VirusScan的控制台,点击"New Task",在对话框的最上面通常就有一个文本框,这个文本框就符合我们的要求。现在我们需要一个句柄来控制这个文本框。执行Shatter并且调整窗口的位置是我们仍然可以看到后面的VirusScan窗口。点击"Get cursor window", Shatter将在他的列表中加入一个类似”102f2-Get cursor window”的项目。这是因为我们刚刚要求Windows提供光标下窗口的句柄。移动光标,划过VirusScan的编辑框使Shatter获知目标。Shatter将会清除列表,并且告知我们目标窗口的句柄,在我之行的时候得到的结果是”30270”。这样我们就可以直接控制带有更高权限的窗口。下面让我们贴入shellcore。
第二步:解除输入的限制现在我们已经获得了窗口的句柄,这样就可以发送任意消息给该窗口,他会不加考虑得去执行。首先我们来确认一下是否有足够的空间来执行shellcode。在Shatter中,输入刚才获得的句柄道"Handle"中,限制文本框最大输入值的消息是EM_SETLIMITTEXT。消息中的第一个参数是最大长度限制,第二个参数没有意义。输入4道WPARAM中,输入0到第3个框中,点击EM_SETLIMITTEXT来发送这个消息。在VirusScan的对话框中输入一些字符,我们会发现无法输入超过4个字符。将刚才传送的参数4修改为"FFFFFFFF",并再次发送消息。现在我们理论上可以在文本框中输入超过4G的内容。这样大的空间足够大多数臃肿的shellcode使用。
第三步:注入shellcode下面让我们来尝试粘贴一些东西到文本框中。当然,我们可以在上面按右键并选择粘贴。假如无法做到上面的步骤,我们还可以使用下面的办法。清空文本框,打开记事本。输入一些东西到记事本,并复制到剪贴板中。然后通过Shatter发送一个粘贴剪贴板内容的消息,这个消息的名称是WM_PASTE。消息中的2个参数必须都是0。使用刚才的句柄,点击WM_PASTE,剪贴板的内容就会出现到文本框中。再次点击,将重复粘贴的动作。测试结束,我们来进行注入shellcode的动作。清空VirusScan的文本框,运行一个十六进制编辑器,读入Shatter压缩包中的sploit.bin。这是Jill提供的shellcode,他可以提供一个远程的控制台。他将这个控制台发送到本地的123端口。我们可以打开一个netcat来接收。使用nc –lp 123 来执行,然后回到十六进制编辑器。选中所有的内容(包含最开始的FOON,在后面我们将用到它),并复制到剪贴板。切换到Shatter,点击WM_PASTE/这是你将能看到一些奇怪的字符出现在VirusScan的文本框中。这些就是我们的shellcode。
[1] [2] [3]
第四步:执行shellcode这是唯一的需要一些技能的步骤。打开你的调试器,并且选择avconsol.exe这个进程来调试(以Windbg为例,按F6然后选择相应的进程即可)。接下来,在内存中扫描"FOON"这个字符串。Windbg的相应的命令是s –a 00000001 10000000 “FOON”,不同的调试器的指令可能不一样。记录下字符串在内存中出现的地址,这项工作可能需要一段时间来完成。在我的系统上,shellcode所在的地址为0x00148c28,如果你使用相同的版本,那么将得到接近的地址。关闭调试器,以guest用户登陆,重复步骤1-步骤3,所有的过程都是一样的。不要忘记运行一个netcat来接收shell。看到这里您可能会想,跟踪调试是需要有特权才能来进行的操作。确实如此。然而就想写一个缓冲区溢出程序一样,我们可以在任何系统上执行这步。我们只需要知道shellcode读入的地址是什么,这样在任何运行相同版本的软件的系统上都能使用。事实上,我们通常不需要做这样的步骤。大多数的应用程序都有自己的错误处理句柄(VirusScan当然也有)。当出现违规访问的时候,程序会处理错误以便不崩溃。所以我们贴入成千上万的重复的NOP指令知道最终找到真正需要的地址,并且shellcode得到执行。这样的做法看上去并不是最好,但是确实能达到目的。最后需要发送的消息是WM_TIMER。这是一个稍微有些的并且非常危险的一条消息。在消息的第二个参数中带有计时器回跳的地址,第一个参数是计时器的编号。据我所知,这个消息并不进入消息队列,所以应用程序没有机会来忽略它。这是一件很可怕的事情。所以使用shatter的时候句柄要设置为带有shellcode的VirusScan的文本框。消息的第一个参数为任意,第二个参数为我们用调试器获取的地址加上512字节或者更多。前面输入的shellcode的最开始有1K的NOP指令,我们选择加512字节将命中这些指令的中坚。在我的系统中,使用的地址为0x148c28+0x200=0x148e28。点击WM_TIMER,这时netcat将会接收到一个命令提示符,并且会提示你已经从guest用户提升为LocalSystem用户。
另外的一些技术除上面介绍的方法外,还可以采用其他相同技术但是可能稍微有些复杂的方法。EM_GETLINE消息可以告诉文本框内容复制到消息中给定的地址。
如何修补这是一个非常容易实现的攻击,下面我们来看看如何修补。在我看来,有两种不正规的方法能很快修复这个问题以及一个繁琐但并不能完全解决问题的方法。下文中我讲解释具体的原因。1. 禁止用户枚举窗口。这个方法理论上可行,但是在用户需要知道当前桌面上都有什么窗口的时候就没有办法了。这是我不赞赏该方法的原因。2. 禁止不同权限的应用程序互相发送消息。这个解决方法的含义就是你不能干预在你桌面上运行的任何不是以你身份运行的窗口。这就是说VirusScan及其他大多数常见的个人防火墙都需要重新设计。3. 在消息中加入来源,在应用程序上判断是否处理这个消息。这就需要扩展Win32API。这将使一向非常繁重的工作,但仍然无法解决这个问题。缓冲区溢出的问题人们已经研究了很多年,但是现在利用这个问题进行的攻击仍然很普遍。
为什么说这是一个问题当微软收到这个文章的时候,他们给我一个回复说他们应觉察到这个类型的攻击,但是他们并不认为这是一个漏洞。我认为这个观点是错误的。微软提出了2点理由:a)需要物力上接触到你的计算机;b)需要在计算机上带有某些恶意程序。他们说的是事实,我非常同意。但是他们忽视了利用这个缺陷可以提升权限的事实。如果用户以guest的权限访问计算机,利用这个攻击就能获取LocalSystem的权限。微软将获取访问权后使用hk.exe、ErunAsX(AKA DebPloit)、iishack.dll这些可以提升权限的程序都定义为安全漏洞并且提供了补丁进行修复。通常的情况下在公司的计算机的操作都被限制得很严格,很多操作都因为没有权限而无法进行。如果某个机器受到shatter攻击的影响,那么用户可以获得LocalSystem权限然后为所欲为。更糟糕的是终端服务程序或者Citrix同样受到影响。想象一下一个出于某种原因提供终端服务的公司,即使不愿意给用户真实的权限,用户仍然可以使用shatter攻击来获得比Administrator更高的LocalSystem权限。在公众可以访问的计算机上这更是一个问题。这并不需要物理上的接触,我利用终端服务成功的攻击了一台数百英里以外的一台机器。真实的情况是微软很清楚他们无法修复这个缺陷。自从1993年7月起,微软就开始在WindowsNT3.5上使用Win32API。微软无法改变这个事实。唯一的解决方法是禁止在桌面上以比当前登陆用户权限高的身份来运行程序。微软认为桌面是系统安全的分界线,任何在桌面上的窗口都定义为不受信任。这是事实,但实在是窗系统上他们违背了这个规则。在视窗系统上有无数的窗口以LocalSystem身份执行。可以使用shatter来检验这点,所有列出的没有命名的窗口都是有可能以LocalSystem身份运行的。某些无法看到的窗口(比如DDE server)一定是用这个身份执行的。所谓的安全的边界线已经不存在了。
只有Win32系统受到这个漏洞影响吗?应该是的。对抗微软视窗系统的另一种主流视窗系统是Xwindow。X使用的是同样的基本技术,消息队列在窗口间互相传递消息。但是最主要的一个差别在X上每个窗口只是一个空白的页面,应用程序可以在页面上做任意的操作。Win32系统上,每个窗口都有相应的权限,X上窗口只是一个图片。在X系统上,当你点击某个控制点的时候,实际上是在点击周围的窗口。应用程序来判断鼠标光标下面是否有控制点并且给出相应的回应。第二点,更重要的区别是在X系统上,消息只是一个通知并不是命令。你无法只靠消息来命令某个X窗口做什么操作。你无法命令他粘贴剪贴板内容,无法命令他改变输入限制,当然更不可能告诉他跳转到内存某处然后开始执行指令。你唯一能做到的只是通过鼠标或者键盘指令来粘贴剪贴板内容。当然,理论上仍然有针对X进行攻击的可能,但是在实际操作上会非常的困难。你可以给一个应用程序发送大量的假消息来看看他的回应,你可以发送一个不完整的消息给应用程序来看他的回应。实际上的情况是应用程序可以很好的处理这些,他们将选择是否处理这些消息并且依次处理。
(出处:http://www.sheup.com)