Exploiting Millennium MP3 Studio 2.0 with Shellcode Payload

June 8, 2020

(This blog post is not original. It covers my experience and the challenges I encountered while replicating this exploit: https://fullpwnops.com/local-seh-overflow/ in Fu11Shade’s “Windows exploitation pathway” sequence. Unless otherwise stated, quoted text is from Fu11Shade’s blog post. To configure your system to follow along with this tutorial complete: https://fullpwnops.com/immunity-windbg-mona/)

In this tutorial we’ll be exploiting an overflow that occurs when Millennium MP3 Studio 2.0 (install here: https://www.exploit-db.com/exploits/10240) attempts to open files with certain extensions. I completed this tutorial on a Windows 7 64-bit virtual machine.

Structured Exception Handler (SEH) based overflows work in many different ways. In this tutorial we’ll be using a text file to inject the malicious payload into the vulnerable field.

What the heck is a “structured exception handler?” Put rather crudely, a SEH is a piece of code designed to handle certain errors that may occur at runtime. Exception handlers can address both hardware and software faults. Some common handlers deal with issues like failing to free memory blocks, insufficient memory, attempting to access a restricted memory location, and etc.

If an exception arises and none of the handlers can resolve the issue, the program will likely terminate or produce some kind of unexpected output.

There are two SEH mechanisms:

  1. Exception handlers: blocks which can respond to or dismiss the exception
  2. Termination handlers: blocks which are always called, whether an exception causes termination or not

When an exception is thrown that a handler recognizes, the handler can either:

  1. Fail to recognize the exception and pass control to other handlers
  2. Recognize the exception but dismiss it
  3. Recognize the exception and handle it

Let’s run through how this SEH exploit will work — much of this is to be explained:

  1. We attach the Millennium process to Immunity so we can observe the buffer overflow and the effects of the vulnerability precisely.
  2. When our malicious file is opened, the application will attempt to parse the data.
  3. Fu11Shade tells us that there’s a buffer overflow when this application’s parsing program operates on files with a “.mpf” extension.
  4. So, we need to create a .mpf file that overflows this buffer.
  5. When an exception is raised, control will jump to the first SEH handler.
  6. The buffer overflow will have set the address of the SEH handler to be the address of the POP POP RET sequence.
  7. This will move ESP down the stack twice and return it to EIP.
  8. Presumably, we’ve overwritten this address and EIP now points to a JMP instruction which moves execution to the start of the shellcode.

Let’s get started:

First, we want to attach the Immunity Debugger to the running Millennium MP3 Studio process:

Next, we want to generate the .mpf file for our exploit. We can do this using a python script:

In this script we generate a payload, open a file named “evil.mpf”, and write the payloads the payload to the file object returned by open() (payload_execution).

After running the script we can see the malicious file.

Now let’s try to open evil.mpf from Millenium Studio MP3 while its attached to Immunity:

We can see the EAX and ECX registers being overwritten with A’s.

Furthermore, we can see a “CORRUPT ENTRY” in our SEH chain:

Finally, we can also see the overflow in Immunity’s logs.

Now that we’ve confirmed there’s a buffer overflow vulnerability, we need to calculate the buffer size so we can generate precise shellcode designed to overwrite SEH handlers.

We can use Metasploit’s pattern create tool to generate a cyclic pattern that will help you identify where data starts being overwritten:

Note: I had issues installing the Metasploit framework on my Windows virtual machine (Metasploit community is no longer offered) and opted to use the Metaploit framework that comes built-in with Kali Linux.

Now, we should attach the Millennium process to Immunity and open our new malicious file:

We can see registers being overwritten by our pattern.

Now, lets run the “findmsp” command. Findmsp will “find all instances or certain references to a cyclic pattern in memory” (corelan.be). If you inject a cyclic pattern and crash your application you can run findmsp to obtain the following information (corelan.be):


  1. Locations where the cyclic pattern can be found and how long that pattern is.
  2. Registers that are overwritten with a 4-byte cyclic pattern and the offset required to overwrite the register.
  3. Registers that point into a cyclic pattern, the offset, and the remaining size of the pattern.
  4. SEH records overwritten with 4-bytes of a cyclic, offset, and size.
  5. Pointers on the current thread stack, into a cyclic pattern (offset + size).
  6. Parts of a cyclic pattern on the stack, the offset from the beginning of the pattern and the size of the pattern.


We can see a SEH handler being overwritten:

In order to exploit this “we need to obtain a POP POP RET gadget.” Using we can accomplish this using mona by running “!mona seh -n” in Immunity. This command will search through the program for the needed sequence which will “return execution flow back to the structured exception handler.”

At first I didn’t know what a POP POP RET gadget really was or why we needed it — so let’s explore that a bit.

According to dkalemis.wordpress.com, exploit writers often search for this sequence “because it is an essential part of their exploit.” Apparently, “POP POP RET is the sequence of instructions needed in order to create SEH exploits.” Notably, the registers to which the popped values go is not of critical importance to whether the exploits succeed. What matters most is that ESP is moved up the address space twice (8 bytes — each position is 4-bytes on a 32-bit architecture), and that a RET instruction is executed. Therefore, either a “POP EAX, POP EBX, RET, or POP ECX, POP ECX, RET, or POP EDX, POP EAX, RET, (and so on) will do.”

Each time a RET occurs, “the contents of the address ESP points at are put in EIP and executed,” (dkalemis). So, the attacker knows that the address of ESP + 8 is going to be put into EIP and executed.

But why is it important that ESP be moved down the stack twice? Why can’t we just overwrite the SEH handler instructions with shellcode since control jumps there anyways when an exception is raised?

Because there are SafeSEH safeguards that protect against this.

According to Dkalemis, SEH’s are “a linked list of records with each record corresponding to an exception handler.” The first field of the record is a pointer to the next record and the second field is the address of the exception handler itself.

SEH exploits are based on the fact that the attacker can “alter a portion of the stack and put values there that can misdirect the execution of the SEH handler after an exception is raised,” (dkalemis).

So, let’s run through how a POP POP RET gadget would work from the top:

  1. After a buffer overflow is raise execution jumps to the address pointed to by the first SEH handler.
  2. The buffer overflow set the address of the SEH handler to be the address of the POP POP RET sequence.
  3. So now EIP will be set to the value of ESP + 8 bytes which will be a jmp instruction to the start of the shellcode.

Moving back to the tutorial now.

Our final python script, which includes the POP POP RET gadget, will look like this:

Notice that our payload now also contains a NOP sled.

Now, when we run the final version of the application we can get a calculator to pop up.

Explore more insights