-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathftp-bounce.nse
224 lines (203 loc) · 4.67 KB
/
ftp-bounce.nse
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
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
local coroutine = require "coroutine"
local nmap = require "nmap"
local shortport = require "shortport"
local string = require "string"
description=[[
Checks to see if an FTP server allows port scanning using the FTP bounce method.
]]
author = "Marek Majkowski"
license = "Same as Nmap--See http://nmap.org/book/man-legal.html"
---
-- @args ftp-bounce.username Username to log in with. Default
-- <code>"anonymous"</code>.
-- @args ftp-bounce.password Password to log in with. Default
-- <code>"IEUser@"</code>.
--
-- @output
-- PORT STATE SERVICE
-- 21/tcp open ftp
-- |_ftp-bounce: bounce working!
--
-- PORT STATE SERVICE
-- 21/tcp open ftp
-- |_ftp-bounce: server forbids bouncing to low ports <1025
--
-- PORT STATE SERVICE
-- 21/tcp open ftp
-- |_ftp-bounce: no banner
categories = {"default", "safe"}
portrule = shortport.service("ftp")
line_iterate = function(s)
local line
for line in string.gmatch(s, "([^\n$]*)") do
if #line > 0 then
coroutine.yield(line)
end
end
end
-- returns last ftp code read, or 000 on timeout
get_ftp_code = function(socket)
local fcode = 000
local code = 0
local status
local result
local co
local line
local err
while true do
status, result = socket:receive()
if not status then
break
end
-- read okay!
co = coroutine.create(line_iterate)
while coroutine.status(co) ~= 'dead' do
err, line = coroutine.resume(co, result)
if line then
code = string.match(line, "^(%d%d%d) ")
if not code then
code = "-1"
end
-- io.write(">" .. code .. ":".. line .. "<\n")
if tonumber(code) > 0 then
fcode = tonumber(code)
end
end
end
-- not received good ftp code, try again
if fcode ~= 0 then
break
end
end
-- io.write("## " .. fcode .. "\n");
return fcode
end
local get_login = function()
local user, pass
local k
for _, k in ipairs({"ftp-bounce.username", "username"}) do
if nmap.registry.args[k] then
user = nmap.registry.args[k]
break
end
end
for _, k in ipairs({"ftp-bounce.password", "password"}) do
if nmap.registry.args[k] then
pass = nmap.registry.args[k]
break
end
end
return user or "anonymous", pass or "IEUser@"
end
action = function(host, port)
local socket = nmap.new_socket()
local result;
local status = true
local isAnon = false
local isOk = false
local sendPass = true
local user, pass = get_login()
local fc
socket:set_timeout(10000)
socket:connect(host, port)
-- BANNER
fc = get_ftp_code(socket)
if fc == 0 then
socket:close()
-- no banner
return "no banner"
end
if fc == 421 or (fc >= 500 and fc <= 599) then
socket:close()
-- return "server says you are not allowed to create connection"
return
end
if fc < 200 or fc > 299 then
socket:close()
-- bad code
-- return "bad banner (code " .. fc .. ")"
return
end
socket:set_timeout(5000)
-- USER
socket:send("USER " .. user .. "\r\n")
fc = get_ftp_code(socket)
if (fc >= 400 and fc <= 499) or (fc >= 500 and fc <= 599) then
socket:close()
-- bad code
--return "anonymous user not allowed"
return
end
if fc == 0 then
socket:close()
-- return "anonymous user timeouted"
return
end
if fc ~= 230 and fc ~= 331 then
socket:close()
-- bad code
-- return "bad response for anonymous user (code " .. fc .. ")"
return
end
if fc == 230 then
sendPass = false
end
-- PASS
if sendPass then
socket:send("PASS " .. pass .. "\r\n")
fc = get_ftp_code(socket)
if (fc >= 500 and fc <= 599) or (fc >= 400 and fc <= 499) then
socket:close()
-- bad code
-- return "anonymous user/pass rejected"
return
end
if fc == 0 then
socket:close()
-- return "anonymous pass timeouted"
return
end
if fc ~= 230 and fc ~= 200 then
socket:close()
-- return "answer to PASS not understood (code " .. fc .. ")"
return
end
end
-- PORT scanme.nmap.com:highport
socket:send("PORT 205,217,153,62,80,80\r\n")
fc = get_ftp_code(socket)
if (fc >= 500 and fc <= 599) then
socket:close()
-- return "server forbids bouncing"
return
end
if fc == 0 then
socket:close()
-- return "PORT command timeouted"
return
end
if not (fc >= 200 and fc<=299) then
socket:close()
-- return "PORT response not understood (code " .. fc .. ")"
return
end
-- PORT scanme.nmap.com:lowport
socket:send("PORT 205,217,153,62,0,80\r\n")
fc = get_ftp_code(socket)
if (fc >= 500 and fc <= 599) then
socket:close()
return "server forbids bouncing to low ports <1025"
end
if fc == 0 then
socket:close()
-- return "PORT command timeouted for low port"
return
end
if not (fc >= 200 and fc<=299) then
socket:close()
-- return "PORT response not understood for low port (code " .. fc .. ")"
return
end
socket:close()
return "bounce working!"
end