/
copy_of_file.rb
159 lines (129 loc) · 4.46 KB
/
copy_of_file.rb
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
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
class MetasploitModule < Msf::Auxiliary
include Msf::Exploit::Remote::HttpClient
include Msf::Auxiliary::WmapScanFile
include Msf::Auxiliary::Scanner
include Msf::Auxiliary::Report
def initialize(info = {})
super(update_info(info,
'Name' => 'HTTP Copy File Scanner',
'Description' => %q{
This module identifies the existence of possible copies
of a specific file in a given path.
},
'Author' => [ 'et [at] cyberspace.org' ],
'License' => BSD_LICENSE))
register_options(
[
OptString.new('PATH', [ true, "The path/file to identify copies", '/index.asp'])
])
register_advanced_options(
[
OptInt.new('ErrorCode', [ true, "Error code for non existent directory", 404]),
OptPath.new('HTTP404Sigs', [ false, "Path of 404 signatures to use",
File.join(Msf::Config.data_directory, "wmap", "wmap_404s.txt")
]
),
OptBool.new('NoDetailMessages', [ false, "Do not display detailed test messages", true ])
])
end
def run_host(ip)
conn = true
ecode = nil
emesg = nil
ecode = datastore['ErrorCode'].to_i
dm = datastore['NoDetailMessages']
# Required to calculate error code for each case as special characters amd spaces
# trigger different responses
prestr = [
'Copy_(1)_of_',
'Copy_(2)_of_',
'Copy of ',
'Copy_of_',
'Copy_',
'Copy',
'_'
]
tpathf = normalize_uri(datastore['PATH'])
testf = tpathf.split('/').last
if testf
prestr.each do |pre|
#
# Detect error code
#
begin
randfile = Rex::Text.rand_text_alpha(5).chomp
filec = tpathf.sub(testf,pre + randfile + testf)
res = send_request_cgi({
'uri' => filec,
'method' => 'GET',
'ctype' => 'text/html'
}, 20)
return if not res
tcode = res.code.to_i
# Look for a string we can signature on as well
if(tcode >= 200 and tcode <= 299)
File.open(datastore['HTTP404Sigs'], 'rb').each do |str|
if(res.body.index(str))
emesg = str
break
end
end
if(not emesg)
print_status("Using first 256 bytes of the response as 404 string")
emesg = res.body[0,256]
else
print_status("Using custom 404 string of '#{emesg}'")
end
else
ecode = tcode
print_status("Using code '#{ecode}' as not found.")
end
rescue ::Rex::ConnectionRefused, ::Rex::HostUnreachable, ::Rex::ConnectionTimeout
conn = false
rescue ::Timeout::Error, ::Errno::EPIPE
end
return if not conn
filec = tpathf.sub(testf,pre + testf)
begin
res = send_request_cgi({
'uri' => filec,
'method' => 'GET',
'ctype' => 'text/plain'
}, 20)
if(not res or ((res.code.to_i == ecode) or (emesg and res.body.index(emesg))))
if dm == false
print_status("NOT Found #{filec} #{res.code} [#{wmap_target_host}] [#{res.code.to_i}]")
end
else
if ecode != 400 and res.code.to_i == 400
print_error("[#{wmap_target_host}] Server returned a 400 error on #{wmap_base_url}#{filec} [#{res.code.to_i}]")
else
print_good("[#{wmap_target_host}] Found #{wmap_base_url}#{filec} [#{res.code.to_i}]")
report_web_vuln(
:host => ip,
:port => rport,
:vhost => vhost,
:ssl => ssl,
:path => "#{filec}",
:method => 'GET',
:pname => "",
:proof => "Res code: #{res.code.to_s}",
:risk => 0,
:confidence => 100,
:category => 'file',
:description => 'Copy file found.',
:name => 'copy of file'
)
end
end
rescue ::Rex::ConnectionRefused, ::Rex::HostUnreachable, ::Rex::ConnectionTimeout
rescue ::Timeout::Error, ::Errno::EPIPE
end
end
end
end
end