1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
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
|