菜鸟版exploit编写指南续【转】


上次写的那篇文章,有好多东西是慌里慌张地没有说清楚。究其原因,说出来不怕大家笑话,我是为了骗点稿费给MM买东西,所以写才会写得这么急。在接受了黑 防老编独行者さんま一番教育后,我深刻地认识到老编,哦~不不,读者才是一切的硬道理。为了显示骗稿费的诚意,我决定续貂一回,作为上一篇的补偿,这篇将 会更详细一点。

四月份微软给的补丁,一下子补了二十几个漏洞,其中有一个lsasrv.dll的远程溢出,就是被用来做“震荡波”蠕虫的那个,算是被大家研究得最多的。 关于这个漏洞的远程利用,mslug在安全焦点(https://www.xfocus.net/bbs/index.php?act=ST&f =6&t=35712)有一个详细的分析,更为简单的本地利用方法,我们在下面说说看。

获得了这个漏洞的消息,首先是要想办法触发这个漏洞。按照eEye的文档,传递给DsRoleUpgradeDownlevelServer函数的第一个 参数以超长的字符串,就会发生溢出,再仔细看看,这个参数在2k和XP下是不一样的,XP下面可以直接是ASCII,但是2k下面必须是UNICODE的 字串。我们假定就在win2k下面利用的吧,先写出一个能够触发溢出的C++程序。嗯,关于这种触发漏洞的程序的写法,我觉得还是要有一个积累的过程先, 一时半会儿是说不太清楚的,这里索性直接给出一个,以后的工作就在上面改。而且还有一点,这种能够触发溢出的程序,往往在别人发布漏洞的时候会给出(叫做 proof of concept的东西),像我们这样的菜鸟,能在第一时间内找到然后修改成我们能够用的就好了,呵呵~

能够触发漏洞的程序我已经做成了1.cpp,估计能在配套光盘中找到。这个程序尽管不长,但要是我贴在正文里面骗取千字八十元的稿费,独行者さんま一定会 背着菜刀乘最近的一趟Z1到上海来砍我的。……话说回来,我想你应该已经找到了这个程序,确认你的机器是win2k而且没有补上,打开VC编译通过……什 么,你点了运行?好吧,你应该可以看到一个60秒重起的对话框了(图一),这个溢出被触发后,lsass.exe因为无法处理的异常而被迫终止,接着整个 操作系统也会跟着出问题,所以,你还是等等吧~

乘这个空当儿,来说说这种漏洞的调法。一般的溢出要是对系统没有太大的影响(比如Serv-U之类),大多都在自己机器上调试,而如果是这种涉及到内核或 者是关键进程的漏洞,调一次就重起一次相当的麻烦,高手们多半都会在VMWare中的虚拟机器上调试。如果内存足够,你也可以试试看在VMWare上面装 上N个操作系统,到时候也不用辛辛苦苦地去找系统环境,所有的东西都可以在自己的机器上搞定。关于VMWare的使用方法,我想可以google一下,或 者跪求大虾们在百忙之中抽空写文章指导一下我们——很多人一起跪求,高手应该是会答应的吧。

你的机器也差不多重起完了,打开利器Ollydbg,文件-〉附加,选中lsass.exe。为什么是lsass.exe呢?你看看刚才的那个图一,显示 异常终止的进程是lsass.exe,所以我们要附加调试它。相应的,如果是services.exe异常终止,你就去附加services.exe,如 果是winlogon.exe那就附加winlogon.exe。

等ollydbg加载完所有的模块以后,按一下F9让lsass.exe继续运行,我们再回过头去修改1.cpp。溢出已经顺利触发,下一步应该是精确定位溢出点,如果忘了怎样去定位,我们马上来复习一下:

for(i=0; i<MAXLEN-1; i++)
buf[2*i] = 'A';

这一段,原来是填充的大量的'A',按照我们上次说的两次定位法,把这里反复填充上ASCII码为100到200的数,这样子改:

for(i=0; i<MAXLEN-1; i++)
buf[2*i] = (char)(i % 100 + 100);

编译后运行(光盘中的2.cpp)。扑通,ollydbg跳了出来,显示的错误信息是“访问违反:写入到[00960000] -使用[Shift+F7/F8/F9]键跳过异常以继续执行程序”,这时候错误的信息已经被ollydbg监测到,而且可以调试。我们要继续往下,看看 到底是哪些数据覆盖到了EIP,按一下Shift+F9,ollydbg的错误信息变成了“访问违反:正在执行[93929190] -使用[Shift+F7/F8/F9]键跳过异常以继续执行程序”(图三)。呵呵,关键的地方出来了,赶快记录下数据0x93929190,然后关掉 ollydbg,等待机器重起吧。

嗯,乘这个空当儿,可以拿出前几期的exploit编写指南来看,下一步定位是怎样的。这一次的重起代价是获得了溢出点的低位值,下一次要获得溢出点的高位值,然后就可以定位成功,接下去就要寻找内存中的指令码,跳转后就是连接shellcode获得控制权了。

又重起了一次(汗)。还是按照前面一次的步骤,打开利器Ollydbg,文件-〉附加,选中lsass.exe,F9让它继续执行。刚才说这一次的任务是定位溢出点的高位值,赶快打开VC来修改上次的文件吧!

for(i=0; i<MAXLEN-1; i++)
buf[2*i] = (char)(i / 100 + 100);

对应的地方改成这样(光盘中的3.cpp),编译运行。这次和上次的步骤也一样,出错信息出来后按一下Shift+F9,出来了些许不同的画面,“访问违 反:正在执行[80808080] -使用[Shift+F7/F8/F9]键跳过异常以继续执行程序(图四)。赶快记录啊,0x80808080,这就是高位的地址,按照上次的方法可以算 出具体的地方来。在这之前(肯定是要重起的,我们再多办几件事情好了),看看哪些寄存器在我们传送的数据附近,在坐下角的地址栏里面单击右键,选择前往 -〉表达式,然后依次填eax/ebx/ecx等等,在ebx的附近,全是80/81之类的,很眼熟哈~我们猜想这就是我们的数据。好,关掉 ollydbg,让计算机重起吧!

嗯嗯,乘这个空当儿,我们来说说这个溢出的问题。大家一眼就看出来了吧,和上次的CMail有一个很明显的不一样的地方,上次是寄存器esp指向我们传递 的数据附近,而这次是ebx。对!说起来,这次的溢出,我们的数据覆盖到了seh链,而上次的是一个简单的覆盖栈上的返回地址,然而这些对我们这样子的菜 鸟来说并不重要,我们的想法很简单,如果esp指在我们传递的数据上,那我们就找内存中的call esp或者是push esp/ret,如果是ebx指在我们传递的数据上,那我们就找内存中的call ebx或者是push ebx/ret,如果发现还有其它的情况(真有其他的情况,不骗你,比如那个perl的问题),依葫芦画瓢就是。反正在精确定位的溢出点上填上相应的地址 就可以,对了,这里说起精确的定位地址,还没有计算呢。

(0x80 - 100) * 100 + 0x90 + 100 = 2844

也就是说在程序3.cpp中,在i为2844开始的地方填上一个内存中的call ebx或者有相同功能的地址就可以,还是上次说的lion那个地址0x7FFA1571,修改3.cpp为4.cpp(还是见光盘),在相应的位置上填充这个地址:

buf[2*2844] = 0x71;
buf[2*2845] = 0x15;
buf[2*2846] = 0xFA;
buf[2*2847] = 0x7F;

还记得上次说的吗,数据要高位取反,写出来就是这个样子了。按照前面说了很多次的步骤,ollydbg附加到lsass.exe,运行VC程序(4.cpp),然后F9,看看我们可爱的ollydbg告诉我们什么?(图五)

执行到我们的代码上了!不要怀疑,确实执行到我们提交的东西上去了,尽管出了错——我们下一步就是要消除这最后一点错误。来看看执行到了什么地方:在坐下 角的地址栏里面单击右键,选择前往-〉表达式,填上eip。注意到了没有,eip执行到的地方,数据刚好是80 80 80 80 71 15 FA 7F,就在我们填写的那个地址0x7FFA1571的前四个字节,算一下2844-4=2880,也就是说对应到我们的程序上面去,i=2880开始,应 该是shellcode。
这里又来了一个问题,i=2280开始,shellcode不能只有4个字节吧,因为i=2884的地方必须得固定。嗯~想想还是容易解决的,我们还有四 个字节可以利用呢,跳过i=2844地方的就可以了嘛,这四个字节写成NOP/NOP/Jmp 4刚刚好四个字节,而且刚好执行过来的时候跳过了必须固定的地方——我们在后面加上shellcode,这个跳转就跳到shellcode上面去了,直观 一点,像这样子:

+---------------+------------+-----------+
| Nop Nop Jmp 4 | 0x7FFA1571 | Shellcode |
+---------------+------------+-----------+
A(i=2840) B(i=2844) C(i=2848)

开始覆盖了某个地方B(这个地方我们不关心,反正按照寄存器来选一个内存中的地址填充就好了),然后跳转后到了地方A,执行到A后又是一个小跳转跳到C,C中放shellcode。

嗯,继续吧。我知道你还要重起一次,乘这个空当儿……我没有什么要说的,你还是喝杯水吧。

好,我们要给这个漏洞以最后一击。在i=2840开始的地方填上NOP/NOP/Jmp 4四个字节的机器码9090EB04,在i=2848开始的地方填上shellcode。用上次的MShell函数生成合适的shellcode,全部加 入到我们最后的成品5.cpp(见光盘中的5.cpp)中去,理论上应该成功了。

在本地监听1111口,不用打开ollydbg了,直接执行程序,看到了么,我们的nc已经给出我们一个shell了!(图六)

应该说到这里这个漏洞的本地利用算是已经写好,下面的事情就是包装包装程序,让用户可以在使用的时候根据实际情况给出connect back的ip和端口号。进一步的,这个漏洞还有其他很有意思的地方,比如,你用ollydbg附加在lsass.exe上面然后执行我们的5.cpp看 看,之前还有一个错误(图七),和上一次的那个栈溢出相同的,是覆盖了返回地址,我们需要用call esp或者类似的指令在内存中的地址去覆盖来获得控制权。这个的精确定位和上面定位的方法一样,大家可以当作练习做来看看。

回顾一下我们这次菜鸟之旅的心得:

1、如果我们能够控制eip的内容,就能获得控制权。在这个时候我们要去看哪个寄存器指向我们发送的数据,然后根据寄存器选定一个内存中的地址(这个地址 的内容应该是call XXX的指令码)来覆盖那个溢出点。具体是esp还是ebx对我们来说不是很重要,除开这两种方式,如果是其他的寄存器比如esi、edi等也可以举一反 三。
2、执行到我们发送的数据上后,如果发现有不能更改的数据,那我们就想办法跳过去。

总之,菜鸟也是有菜鸟的乐趣,在别人公布了漏洞没有公布利用程序之前,有很多人都不会注意去打补丁的,如果能够最快速度写出exploit来自己用,还是 能获得很好的机器(呵呵~)。我就是用自己写的本地溢出来提升权限获得了对某台机器的控制权,成功的那一瞬间,还是非常有成就感的。

posted on 2007-08-24 16:41  dhb133  阅读(738)  评论(0编辑  收藏  举报

导航