local bin = require "bin"
local io = require "io"
local msrpc = require "msrpc"
local smb = require "smb"
local string = require "string"
local stdnse = require "stdnse"
description = [[
Attempts to print text on a shared printer by calling Print Spooler Service RPC functions.
In order to use the script, at least one printer needs to be shared
over SMB. If no printer is specified, script tries to enumerate existing
ones by calling LANMAN API which might not be always available.
LANMAN is available by default on Windows XP, but not on Vista or Windows 7
for example. In that case, you need to specify printer share name manually
using printer
script argument. You can find out available shares
by using smb-enum-shares script.
Later versions of Windows require valid credentials by default
which you can specify trough smb library arguments smbuser
and
smbpassword
or other options.
]]
---
-- @usage nmap -p 445 --script=smb-print-text --script-args="text=0wn3d"
--
-- @output
-- |_smb-print-text: Printer job started using MyPrinter printer share.
--
-- @args printer Printer share name. Optional, by default script tries to enumerate available printer shares.
-- @args text Text to print. Either text or filename need to be specified.
-- @args filename File to read text from (ASCII only).
--
author = "Aleksandar Nikolic"
license = "Same as Nmap--See https://nmap.org/book/man-legal.html"
categories = {"intrusive"}
hostrule = function(host)
return smb.get_port(host) ~= nil
end
action = function(host,port)
local status, smbstate
local text = stdnse.get_script_args(SCRIPT_NAME .. '.text')
local filename = stdnse.get_script_args(SCRIPT_NAME .. '.filename')
if (not text) and (not filename) then
stdnse.debug1("Script requires either text or filename script argument.")
return false
end
local text_to_print
if text then
text_to_print = text
else
-- read text from file
local file = io.open(filename, "rb")
text_to_print = file:read("*all")
end
status, smbstate = msrpc.start_smb(host, msrpc.SPOOLSS_PATH,true)
if(status == false) then
stdnse.debug1("SMB: " .. smbstate)
return false, smbstate
end
local bind_result
status, bind_result = msrpc.bind(smbstate,msrpc.SPOOLSS_UUID, msrpc.SPOOLSS_VERSION, nil)
if(status == false) then
msrpc.stop_smb(smbstate)
stdnse.debug1("SMB: " .. bind_result)
return false, bind_result
end
local printer = stdnse.get_script_args(SCRIPT_NAME .. '.printer')
-- if printer not set find available printers
if not printer then
stdnse.debug1("No printer specified, trying to find one...")
local lanman_result
local REMSmb_NetShareEnum_P = "WrLeh"
local REMSmb_share_info_1 = "B13BWz"
status, lanman_result = msrpc.call_lanmanapi(smbstate,0,REMSmb_NetShareEnum_P,REMSmb_share_info_1,bin.pack("ss",0x01,65406))
if status == false then
stdnse.debug1("SMB: " .. lanman_result)
stdnse.debug1("SMB: Looks like LANMAN API is not available. Try setting printer script arg.")
return false
end
local parameters = lanman_result.parameters
local data = lanman_result.data
local pos, status, convert, entry_count, available_entries = bin.unpack("s",data,pos+14)
pos, name = bin.unpack(" printer share.", printer)
end