首页
论坛
课程
招聘
[原创]exploit_me_A的shellcode构造与突破
2008-1-2 13:23 4362

[原创]exploit_me_A的shellcode构造与突破

2008-1-2 13:23
4362
这次exploit_me本来很感兴趣的,可是好像日子选太好了啊 ,都是聚会,结果B就没有去做了,A也就没必要提交了,偶的书啊。

      其实我对shellcode并没有什么研究,也就马马虎虎跟过一个ani漏洞的shellcode,就一点皮毛,讲的不对,还望多多指正。

      先来看看exploit_me_A溢出发生的函数
@exploit__00401000:                          ;<= Procedure Start

        sub     esp, 0C8h
        or      ecx, 0FFFFFFFFh
        xor     eax, eax
        lea     edx, dword ptr [esp]
        push    esi
        push    edi
        mov     edi, dword ptr [esp+0D4h]
        push    040904Ch         ; ASCII "********************"
            
; 源字符串计数,不能含有null字符,否则即被截断
        repne   scas byte ptr es:[edi]       ; edi=pszRecv 
        not     ecx                          ; nRecvLen
        sub     edi, ecx                    
        mov     eax, ecx
        mov     esi, edi
        mov     edi, edx
        shr     ecx, 2
        rep     movs dword ptr es:[edi], dword ptr [esi]
        mov     ecx, eax
        and     ecx, 3
        rep     movs byte ptr es:[edi], byte ptr [esi]
        ……

用hex——rays方便的可以看到c代码是
int exploit__00401000(const char* pszRecv)
{
	char szRecv[200];
	strcpy(szRecv,pszRecv);
……
}

明显,pszRecv没有被经过边界检查就拷给了szRecv,而szRecv仅仅只有200 bytes,当pszRecv中长度大于200时,即导致溢出发生
更正
可以确定溢出的条件:
pszRecv必须大于200字节才能溢出,且不能含null字符

构造shellcode

21世纪,shellcode什么最重要--通用性,地球人都知道
以下言论可能直接导致众人笑偶门外汉。
shellcode其实通用性非常局限,无论是暴力搜索kernel32 base还是peb取kernel32 base,最后还是要借助jmp ebx或者jmp esp,那就不得不硬编码,windows补丁如此最多。。。通用是不是有局限了呢(偶的半sp2中kernel32基地址就是0x4FAD0000)。

偶要求不是太高,有没有可以在xp全系列里通用的jmp esp或jmp ebx地址呢(包括任意不完全补丁的xp)?可能会有,但是目前为止还没有被统计出来吧,xp补丁无穷技术就是最好的shellcode防火墙

要在xp全系列通用?开始有人要嘘了,还好,针对这个特定的exploit_me_A,确实可以做到!

偶们知道exe文件基地址在编译时就是指定的,默认是0x400000,不象dll,exe基地址在运行是也不会改变(说的有点心虚,高手快来指正),那exe文件中某个retn的地址是不是就是确定的呢

哈哈,好了,我们回顾下溢出发生的函数
int exploit__00401000(const char* pszRecv)
{
	char szRecv[200];
	strcpy(szRecv,pszRecv);
……
}


pszRecv,就是他
“伟大的Recv指针,他继承了指针的光荣的传统,p-s-z-R-e-c-v,这一刻他灵魂附体!在这一刻!他不是一个人在战斗!他不是一个人!!”
我们可以放弃esp,放弃ebx,放弃abdce了!

当这个溢出函数被调用时,堆栈为
Esp-> return Address
          pszRevc
          ……


,只要将return Address覆盖为exploit_me_A中任意一个retn地址!就控制eip流向shellcode了!

按照前面的利用方法,shellcode被构造成

< 200 bytes ><4 bytes>
| shellcode1   |   pRetn  |

retn就选溢出发生函数function_00401000的好了
00401000   sub     esp, 0C8
......
004010A4   retn


retn地址最高字节为00,这样shellcode为
< 200 bytes ><4 bytes>
| shellcode1   |A4104000|

遇0截断,实际shellcode只有203字节

幸好,function_00401000调用处只有一个,覆盖的返回地址始终为0x00401255,最高字节亦始终为00

所以不怕返回地址最高字节没有覆盖到而导致控制eip失败。

0040124B   lea     edx, dword ptr [esp+34]         ;  loc_40124B
0040124F   push    edx
00401250   call    00401000
00401255   add     esp, 4
......


留下一个问题,实际可执行的shellcode被限制成了200字节,因为不能覆盖pszRevc。


突破200字节限制


向上查找红色句子--溢出的限制条件--pszRecv必须大于200字节才能溢出,且不能含null字符

把限制条件转换为利用条件吧

再回顾下溢出发生的函数
int exploit__00401000(const char* pszRecv)
{
	char szRecv[200];
	strcpy(szRecv,pszRecv);
……
}

shellcode被执行实在pszRecv指向的堆栈中,而导致溢出覆盖的是在szRecv指向的堆栈中,
所以,只要从pszRecv拷到szRecv的shellcode满足溢出长度即可

这样,可以把把shellcode构造成这样

<         200 bytes      > < 4 bytes > <512-204bytes>
|shellcode1...jmp $+4 | A4104000 |     shellcode2    |

好了,突破可执行shellcode 200字节限制了

0040120B   push    eax                             ; /Flags => 0
0040120C   rep     stos dword ptr es:[edi]         ; |
0040120E   lea     ecx, dword ptr [esp+38]         ; |
00401212   push    200                             ; |BufSize = 200 (512.)
00401217   push    ecx                             ; |Buffer
00401218   push    ebx                             ; |Socket
00401219   call    dword ptr [<&WS2_32.#16>]       ; \recv
...


现在,shellcode扩展到512字节了,这个长度可以做很多事了

512能不能突破?留给大家玩了

附件里的shellcode我直接用了导入表
名称位于 exploit_, 条目 10
 地址=00408024
 区段=.rdata
 类型=输入    (已知)
 名称=KERNEL32.LoadLibraryA

名称位于 exploit_, 条目 11
 地址=00408028
 区段=.rdata
 类型=输入    (已知)
 名称=KERNEL32.ExitProcess

名称位于 exploit_, 条目 46
 地址=004080B4
 区段=.rdata
 类型=输入    (已知)
 名称=KERNEL32.GetProcAddress

[2022冬季班]《安卓高级研修班(网课)》月薪三万班招生中~

上传的附件:
收藏
点赞0
打赏
分享
最新回复 (12)
雪    币: 820
活跃值: 活跃值 (189)
能力值: (RANK:500 )
在线值:
发帖
回帖
粉丝
humourkyo 活跃值 12 2008-1-2 13:33
2
0
可以确定shellcode的条件:
shellcode必须大于200字节,且不能含null字符

其他没看  只看到LZ这句 就觉得不对.  因为至少我那个SHELLCODE是小于200字节  并且成功溢出了的
雪    币: 110
活跃值: 活跃值 (248)
能力值: ( LV13,RANK:1050 )
在线值:
发帖
回帖
粉丝
combojiang 活跃值 26 2008-1-2 13:37
3
0
哈,学习学习
雪    币: 215
活跃值: 活跃值 (11)
能力值: ( LV8,RANK:130 )
在线值:
发帖
回帖
粉丝
edisonH 活跃值 3 2008-1-2 13:39
4
0
不管用bbs还是bbs1,总是断断续续不能访问,多发了一个,删另一个吧
雪    币: 215
活跃值: 活跃值 (11)
能力值: ( LV8,RANK:130 )
在线值:
发帖
回帖
粉丝
edisonH 活跃值 3 2008-1-2 13:40
5
0
还要请教怎么小于200溢出
雪    币: 820
活跃值: 活跃值 (189)
能力值: (RANK:500 )
在线值:
发帖
回帖
粉丝
humourkyo 活跃值 12 2008-1-2 13:45
6
0
太有意思了   forgot那里写的是 一定要小于200字节  你这里却相反
雪    币: 215
活跃值: 活跃值 (11)
能力值: ( LV8,RANK:130 )
在线值:
发帖
回帖
粉丝
edisonH 活跃值 3 2008-1-2 13:52
7
0
谢谢提醒   我说错了 是大于200字节才能溢出

无语了
雪    币: 6766
活跃值: 活跃值 (1121)
能力值: (RANK:520 )
在线值:
发帖
回帖
粉丝
netwind 活跃值 13 2008-1-2 13:53
8
0
shellcode 指的是具有执行功能的 指令的16进制代码

你所说的大于200字节应该是你构造的恶意字符串的长度,它里面包括shellcode

要想使跨平台 那么恶意串必须小于200字节

因为
要跨平台 就用程序本身的地址就可以了 程序本身地址有00 ,会截断串所以 只能做到把返回地址覆盖,后面的就写不到程序里去了

这样shellcode 模式要转变下
方式为SHELLCODE+JUMPADDR
shellcode控制在196字节内完全够了 后面3字节写跳转指令地址 因为程序本身地址如00402364 ,堆栈要覆盖的地址有00,只需要把402364写进去,如果有40了只需要把23,64写进去就可以了.

其实我们可以发现,返回地址下面就是我们shellcode在栈里的地址,所以我们用retn指令地址覆盖,就条到我们shellcode里了.

failwest给的168字节 完全符合
雪    币: 215
活跃值: 活跃值 (11)
能力值: ( LV8,RANK:130 )
在线值:
发帖
回帖
粉丝
edisonH 活跃值 3 2008-1-2 14:00
9
0
作为一个poc 200字节当然是够了  

但是你想做点什么时。。。
雪    币: 6766
活跃值: 活跃值 (1121)
能力值: (RANK:520 )
在线值:
发帖
回帖
粉丝
netwind 活跃值 13 2008-1-2 14:07
10
0
对啊,portbind的 一般都300多字节,
那样只能选择系统地址跳转了 方式为jumpaddr+shellcode
系统的跳转地址具有不通用性
雪    币: 5536
活跃值: 活跃值 (56)
能力值: (RANK:1060 )
在线值:
发帖
回帖
粉丝
forgot 活跃值 26 2008-1-2 14:56
11
0
腰好没烦恼,你要做点什么就再recv一个包,只要tcp不分片
雪    币: 110
活跃值: 活跃值 (248)
能力值: ( LV13,RANK:1050 )
在线值:
发帖
回帖
粉丝
combojiang 活跃值 26 2008-1-2 15:27
12
0
好,这个写的巧:
        memset((char*)szBuffer,0x90,204);
        memcpy((char*)szBuffer,(char*)shellcode,103);
        *(DWORD*)(&szBuffer[200])=0x4010A4;
雪    币: 110
活跃值: 活跃值 (248)
能力值: ( LV13,RANK:1050 )
在线值:
发帖
回帖
粉丝
combojiang 活跃值 26 2008-1-2 15:29
13
0
其实,关于溢出这部分可以做的更活些,ret地址你说了算,要怎么跳便怎么跳。
游客
登录 | 注册 方可回帖
返回