Sitemap

GIMP Heap Overflow Re-Discovery and Exploitation (CVE-2025–6035)

5 min readJun 14, 2025

--

Back in April, I shared a walkthrough on how to make a Ghidra script for spotting suspicious malloc calls. I then put that script to the test in my last post by using it to analyze a known vulnerable program. One of the common questions that came up from this, and one of the things I’ll be reviewing at Black Hat in far more detail, is how to evaluate the findings from this (and other) scripts. The script flagged 6 sketchy malloc calls but I jumped directly to the one identified by Synacktiv by recognizing the function name rather than by examining each call site. I will again put the script to the test against a real world vulnerability but this time I’ll go into more detail by fully confirming exploitability of a recently discovered vulnerability.

Target Selection

I starting by asking an LLM to find a good example:

Finding a Target with an LLM

This looks like a reasonable candidate and so I pulled down a vulnerable Ubuntu package and cracked it open to find the vulnerable program file:

$ apt download gimp=2.10.36-3build3 && dpkg-deb -x gimp*.deb ./vuln

Analyzing the GIMP Plug-In

I found the vulnerable despeckle plugin in ./vuln/usr/lib/gimp/2.0/plug-ins/despeckle/despeckle. I loaded this program into Ghidra, analyzed it, and ran my script and received this console output:

Console Error for Missing malloc

The reason for this is that GIMP uses glib and so rather than malloc, we need the script to look for calls to g_malloc as shown with this update:

Updating the script to look for g_malloc

Re-running the script with that change in place gives us a short list of 4 potentially suspicious g_malloc calls:

Suspicious g_malloc Calls

Reviewing Findings

My next step from here is to load the Decompile plugin and then jump to the first location:

Zoom image will be displayed
Decompile view at suspicious g_malloc

The questionable g_malloc calls use lVar9 which we can see was calculated by multiplying 3 other variables:

  lVar9 = (long)(iVar1 * iVar3 * iVar4);
uVar7 = g_malloc(lVar9);
uVar8 = g_malloc(lVar9);

We can also see in this screenshot that iVar1 and iVar3 are assigned from struct members of a parameter to the function. The parameter is passed as the first argument to an external function gimp_preview_get_position. From the GIMP Developer docs, you can find that the first argument to this is a GimpPreview. With more analysis it should be possible to figure out what values these offsets reference (without looking at source code). One option would be to test under a debugger. Another option is to hunt for other references to this struct offset and then look for log messages or downstream usage to infer what the member variable is.

In this situation, I typically would make a note that these two findings look promising but then move on to analyze the next finding at 00104575:

Zoom image will be displayed
Decompile at next suspicious g_malloc calls

This time we see two more g_malloc calls where the size parameter is calculated from multiplication. Using cursor text highlighting in Ghidra, we can quickly see that these were likely set by an external function gimp_drawable_mask_intersect:

Zoom image will be displayed
Tracing the variables with cursor highlighting

Looking up the documentation for this library call, we see:

gboolean
gimp_drawable_mask_intersect (
GimpDrawable* drawable,
gint* x,
gint* y,
gint* width,
gint* height
)

And so from this, we can recognize that arguments 4 and 5 represent width and height. It’s also worth noting that the third factor in this multiplication came from babl_format_get_bytes_per_pixel. This makes sense in context because the application would want to calculate how many bytes to allocate based on the number of pixels (height times width) times the number of bytes per pixel.

The Bigger Picture

If you look back at the earlier g_malloc calls, they also followed the same format of multiplying two numbers with the bytes per pixel value. It’s not unreasonable to think the values feeding in are actually height and width again. It seems likely that heap memory corruption would result from running this plug-in on an image with a very large canvas. That being said, there could certainly be a variety of factors which complicate or even make this type of bug impossible to exploit. A question to ask in this case is whether the software would even be able to handle such a big drawable area so as to be able to trigger this bug.

Proof of Concept Testing

To answer this question, I turned once again to the LLM and this time asked it to generate a Python script to produce a PNG file with crafted dimensions. I opened the resulting file from GIMP for Windows and it opened without issue allowing me to apply the Despeckle enhancement filter:

Zoom image will be displayed
Can you enhance that?

This lead to a modal window to configure the filter:

Despeckle Plugin Modal

After clicking ok on that dialog and then clicking again on the canvas, I got my crash:

Zoom image will be displayed
GIMP Crash from the PoC File

Conclusions

Most samples are not quite as straightforward as this one, but the general idea, when evaluating results from this malloc checker, is to trace back through the arithmetic inputs looking for bounds checks and considering whether the input is attacker controllable (e.g. tainted). Sometimes there will be practical limits which make it impossible to overflow a variable. A common example of this is when a strlen values are added to compute an allocation size. While technically exploitable, this may require actually supplying many GB of input data which is often impractical.

If you find this kind of analysis interesting and would like to learn more about my techniques for analyzing compiled programs and firmware, I would encourage you to join me this summer in Las Vegas at one of my upcoming Black Hat USA training sessions (or Sat/Sun). During these intensive two-day sessions, I will walkthrough examples like this while giving students time to explore on their own and ask questions. More examples from my training material can be found on my Medium and GitHub profiles under cy1337.

--

--

Craig Young
Craig Young

Written by Craig Young

I’m a 15-year veteran of the infosec industry with 200+ CVEs, two USENIX papers, a Pwnie award, and a bunch of bounties to my name. Currently teaching Ghidra.

Responses (1)