summaryrefslogtreecommitdiffstats
path: root/scripts/smb-print-text.nse
diff options
context:
space:
mode:
Diffstat (limited to 'scripts/smb-print-text.nse')
-rw-r--r--scripts/smb-print-text.nse133
1 files changed, 133 insertions, 0 deletions
diff --git a/scripts/smb-print-text.nse b/scripts/smb-print-text.nse
new file mode 100644
index 0000000..3e6b5f9
--- /dev/null
+++ b/scripts/smb-print-text.nse
@@ -0,0 +1,133 @@
+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 <code>printer</code> 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 <code>smbuser</code> and
+<code>smbpassword</code> or other options.
+
+]]
+---
+-- @usage nmap -p 445 <target> --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,string.pack("<I2I2", 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 status, convert, entry_count, available_entries = string.unpack("<I2 I2 I2 I2", parameters)
+ local pos = 1
+ for i = 1, entry_count, 1 do
+ local name, share_type = string.unpack(">c14 I2", data, pos)
+
+ if share_type == 1 then -- share is printer
+ name = string.unpack("z", name)
+ stdnse.debug1("Found printer share %s.", name)
+ printer = name
+ break
+ end
+ pos = pos + 20
+ end
+ end
+ if not printer then
+ stdnse.debug1("No printer found, system may be unpatched but it needs at least one printer shared to be vulnerable.")
+ return false
+ end
+ stdnse.debug1("Using %s as printer.",printer)
+ -- call RpcOpenPrinterEx - opnum 69
+ local status, result = msrpc.spoolss_open_printer(smbstate,"\\\\"..host.ip.."\\"..printer)
+ if not status then
+ return false
+ end
+ local printer_handle = string.sub(result.data,25,#result.data-4)
+ stdnse.debug1("Printer handle %s",stdnse.tohex(printer_handle))
+ -- call RpcStartDocPrinter - opnum 17
+ status,result = msrpc.spoolss_start_doc_printer(smbstate,printer_handle,"nmap_print_test.txt") -- patched version will allow this
+ if not status then
+ return false
+ end
+ local print_job_id = string.sub(result.data,25,#result.data-4)
+ stdnse.debug1("Start doc printer job id %s",stdnse.tohex(print_job_id))
+
+ -- call RpcWritePrinter - 19
+ status, result = msrpc.spoolss_write_printer(smbstate,printer_handle,text_to_print)
+ if not status then
+ return false
+ end
+ local write_result = string.sub(result.data,25,#result.data-4)
+ stdnse.debug1("Written %s bytes to a file.",stdnse.tohex(write_result))
+
+ status,result = msrpc.spoolss_end_doc_printer(smbstate,printer_handle)
+
+ return string.format("Printer job started using <%s> printer share.", printer)
+end