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
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
|
local brute = require "brute"
local creds = require "creds"
local math = require "math"
local nmap = require "nmap"
local shortport = require "shortport"
local stdnse = require "stdnse"
description=[[
Performs brute force password auditing against the classic UNIX rlogin (remote
login) service. This script must be run in privileged mode on UNIX because it
must bind to a low source port number.
]]
---
-- @usage
-- nmap -p 513 --script rlogin-brute <ip>
--
-- @output
-- PORT STATE SERVICE
-- 513/tcp open login
-- | rlogin-brute:
-- | Accounts
-- | nmap:test - Valid credentials
-- | Statistics
-- |_ Performed 4 guesses in 5 seconds, average tps: 0
--
-- @args rlogin-brute.timeout socket timeout for connecting to rlogin (default 10s)
-- Version 0.1
-- Created 11/02/2011 - v0.1 - created by Patrik Karlsson <patrik@cqure.net>
author = "Patrik Karlsson"
license = "Same as Nmap--See https://nmap.org/book/man-legal.html"
categories = {"brute", "intrusive"}
portrule = shortport.port_or_service(513, "login", "tcp")
-- The rlogin Driver, check the brute.lua documentation for more details
Driver = {
-- creates a new Driver instance
-- @param host table as received by the action function
-- @param port table as received by the action function
-- @return o instance of Driver
new = function(self, host, port, options)
local o = { host = host, port = port, timeout = options.timeout }
setmetatable(o, self)
self.__index = self
return o
end,
-- connects to the rlogin service
-- it sets the source port to a random value between 513 and 1024
connect = function(self)
local status
self.socket = brute.new_socket()
-- apparently wee need a source port below 1024
-- this approach is not very elegant as it causes address already in
-- use errors when the same src port is hit in a short time frame.
-- hopefully the retry count should take care of this as a retry
-- should choose a new random port as source.
local srcport = math.random(513, 1024)
self.socket:bind(nil, srcport)
self.socket:set_timeout(self.timeout)
local err
status, err = self.socket:connect(self.host, self.port)
if ( status ) then
local lport, _
status, _, lport = self.socket:get_info()
if (not(status) ) then
return false, "failed to retrieve socket status"
end
else
self.socket:close()
end
if ( not(status) ) then
stdnse.debug3("ERROR: failed to connect to server")
end
return status
end,
login = function(self, username, password)
local data = ("\0%s\0%s\0vt100/9600\0"):format(username, username)
local status, err = self.socket:send(data)
status, data = self.socket:receive()
if (not(status)) then
local err = brute.Error:new("Failed to read response from server")
err:setRetry( true )
return false, err
end
if ( data ~= "\0" ) then
stdnse.debug2("ERROR: Expected null byte")
local err = brute.Error:new( "Expected null byte" )
err:setRetry( true )
return false, err
end
status, data = self.socket:receive()
if (not(status)) then
local err = brute.Error:new("Failed to read response from server")
err:setRetry( true )
return false, err
end
if ( data ~= "Password: " ) then
stdnse.debug2("ERROR: Expected password prompt")
local err = brute.Error:new( "Expected password prompt" )
err:setRetry( true )
return false, err
end
status, err = self.socket:send(password .. "\r")
status, data = self.socket:receive()
if (not(status)) then
local err = brute.Error:new("Failed to read response from server")
err:setRetry( true )
return false, err
end
status, data = self.socket:receive()
if (not(status)) then
local err = brute.Error:new("Failed to read response from server")
err:setRetry( true )
return false, err
end
if ( data:match("[Pp]assword") or data:match("[Ii]ncorrect") ) then
return false, brute.Error:new( "Incorrect password" )
end
return true, creds.Account:new(username, password, creds.State.VALID)
end,
disconnect = function(self)
return self.socket:close()
end,
}
local arg_timeout = stdnse.parse_timespec(stdnse.get_script_args(SCRIPT_NAME .. ".timeout"))
arg_timeout = (arg_timeout or 10) * 1000
action = function(host, port)
if ( not(nmap.is_privileged()) ) then
stdnse.verbose1("Script must be run in privileged mode. Skipping.")
return stdnse.format_output(false, "rlogin-brute needs Nmap to be run in privileged mode")
end
local options = {
timeout = arg_timeout
}
local engine = brute.Engine:new(Driver, host, port, options)
engine.options.script_name = SCRIPT_NAME
local status, result = engine:start()
return result
end
|