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("a") file:close() 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