Land heyder#2, Refactor namespaces
This commit is contained in:
commit
5d254cc36b
|
@ -8,11 +8,13 @@ module Msf
|
|||
module Gitlab
|
||||
include Msf::Exploit::Remote::HttpClient
|
||||
include Msf::Exploit::Remote::HTTP::Gitlab::AccessTokens
|
||||
include Msf::Exploit::Remote::HTTP::Gitlab::Authenticate
|
||||
include Msf::Exploit::Remote::HTTP::Gitlab::Error
|
||||
include Msf::Exploit::Remote::HTTP::Gitlab::Form
|
||||
include Msf::Exploit::Remote::HTTP::Gitlab::Groups
|
||||
include Msf::Exploit::Remote::HTTP::Gitlab::Helpers
|
||||
include Msf::Exploit::Remote::HTTP::Gitlab::Import
|
||||
include Msf::Exploit::Remote::HTTP::Gitlab::Signin
|
||||
include Msf::Exploit::Remote::HTTP::Gitlab::Rest
|
||||
include Msf::Exploit::Remote::HTTP::Gitlab::Version
|
||||
|
||||
def initialize(info = {})
|
||||
|
|
|
@ -2,53 +2,6 @@
|
|||
|
||||
# GitLab Access Tokens mixin
|
||||
module Msf::Exploit::Remote::HTTP::Gitlab::AccessTokens
|
||||
# Create Gitlab access access token
|
||||
#
|
||||
# @return [String,nil] Gitlab personal access token if created, nil otherwise
|
||||
def gitlab_create_personal_access_token
|
||||
res = send_request_cgi({
|
||||
'method' => 'POST',
|
||||
'uri' => normalize_uri(target_uri.path, '/-/profile/personal_access_tokens'),
|
||||
'keep_cookies' => true,
|
||||
'vars_post' => {
|
||||
'personal_access_token[name]' => Rex::Text.rand_text_alphanumeric(8),
|
||||
'personal_access_token[expires_at]' => '',
|
||||
'personal_access_token[scopes][]' => 'api',
|
||||
'commit' => 'Create personal access token'
|
||||
},
|
||||
'headers' => {
|
||||
'X-CSRF-Token' => gitlab_helper_extract_csrf_token(path: '/-/profile/personal_access_tokens', regex: /name="csrf-token" content="(.*)"/)
|
||||
}
|
||||
})
|
||||
|
||||
raise Msf::Exploit::Remote::HTTP::Gitlab::Error::ClientError.new message: 'Request timed out' unless res
|
||||
|
||||
raise Msf::Exploit::Remote::HTTP::Gitlab::Error::ClientError, "Failed to create access token. Unexpected HTTP #{res.code} response." unless res.code == 200
|
||||
|
||||
token = JSON.parse(res.body)['new_token']
|
||||
|
||||
return token if token
|
||||
|
||||
nil
|
||||
end
|
||||
|
||||
# Revoke Gitlab personal access token
|
||||
#
|
||||
# @return [nil,GitLabClientError] nil if revoke, Msf::Exploit::Remote::HTTP::Gitlab::GitLabClientError otherwise
|
||||
def gitlab_revoke_personal_access_token(personal_access_token)
|
||||
res = send_request_cgi({
|
||||
'method' => 'DELETE',
|
||||
'uri' => normalize_uri(target_uri.path, '/api/v4/personal_access_tokens/self'),
|
||||
'ctype' => 'application/json',
|
||||
'headers' => {
|
||||
'PRIVATE-TOKEN' => personal_access_token
|
||||
}
|
||||
})
|
||||
|
||||
raise Msf::Exploit::Remote::HTTP::Gitlab::Error::ClientError.new message: 'Request timed out' unless res
|
||||
|
||||
raise Msf::Exploit::Remote::HTTP::Gitlab::Error::ClientError, "Failed to revoke access token. Unexpected HTTP #{res.code} response." unless res.code == 204
|
||||
|
||||
nil
|
||||
end
|
||||
include Msf::Exploit::Remote::HTTP::Gitlab::Form::AccessTokens
|
||||
include Msf::Exploit::Remote::HTTP::Gitlab::Rest::V4::AccessTokens
|
||||
end
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
# -*- coding: binary -*-
|
||||
|
||||
module Msf::Exploit::Remote::HTTP::Gitlab::Authenticate
|
||||
include Msf::Exploit::Remote::HTTP::Gitlab::Form::Authenticate
|
||||
end
|
|
@ -0,0 +1,2 @@
|
|||
module Msf::Exploit::Remote::HTTP::Gitlab::Form
|
||||
end
|
|
@ -0,0 +1,34 @@
|
|||
# -*- coding: binary -*-
|
||||
|
||||
# Create a Gitlab Access Token via form
|
||||
module Msf::Exploit::Remote::HTTP::Gitlab::Form::AccessTokens
|
||||
# Create Gitlab access access token
|
||||
#
|
||||
# @return [String,nil] Gitlab personal access token if created, nil otherwise
|
||||
def gitlab_create_personal_access_token
|
||||
res = send_request_cgi({
|
||||
'method' => 'POST',
|
||||
'uri' => normalize_uri(target_uri.path, '/-/profile/personal_access_tokens'),
|
||||
'keep_cookies' => true,
|
||||
'vars_post' => {
|
||||
'personal_access_token[name]' => Rex::Text.rand_text_alphanumeric(8),
|
||||
'personal_access_token[expires_at]' => '',
|
||||
'personal_access_token[scopes][]' => 'api',
|
||||
'commit' => 'Create personal access token'
|
||||
},
|
||||
'headers' => {
|
||||
'X-CSRF-Token' => gitlab_helper_extract_csrf_token(path: '/-/profile/personal_access_tokens', regex: /name="csrf-token" content="(.*)"/)
|
||||
}
|
||||
})
|
||||
|
||||
raise Msf::Exploit::Remote::HTTP::Gitlab::Error::ClientError.new message: 'Request timed out' unless res
|
||||
|
||||
raise Msf::Exploit::Remote::HTTP::Gitlab::Error::ClientError, "Failed to create access token. Unexpected HTTP #{res.code} response." unless res.code == 200
|
||||
|
||||
token = JSON.parse(res.body)['new_token']
|
||||
|
||||
return token if token
|
||||
|
||||
nil
|
||||
end
|
||||
end
|
|
@ -1,7 +1,7 @@
|
|||
# -*- coding: binary -*-
|
||||
|
||||
# GitLab session mixin
|
||||
module Msf::Exploit::Remote::HTTP::Gitlab::Signin
|
||||
module Msf::Exploit::Remote::HTTP::Gitlab::Form::Authenticate
|
||||
# performs a gitlab login
|
||||
#
|
||||
# @param user [String] Username
|
||||
|
@ -36,7 +36,7 @@ module Msf::Exploit::Remote::HTTP::Gitlab::Signin
|
|||
|
||||
# performs a gitlab logout
|
||||
#
|
||||
# @return [Bolean,GitLabError] True if sign out, Msf::Exploit::Remote::HTTP::Gitlab::Error otherwise
|
||||
# @return [Boolean,GitLabError] True if sign out, Msf::Exploit::Remote::HTTP::Gitlab::Error otherwise
|
||||
def gitlab_sign_out
|
||||
csrf_token = gitlab_helper_extract_csrf_token(
|
||||
path: '/',
|
|
@ -2,50 +2,5 @@
|
|||
|
||||
# GitLab Groups mixin
|
||||
module Msf::Exploit::Remote::HTTP::Gitlab::Groups
|
||||
# Create a new group
|
||||
#
|
||||
# @return [String,nil] Group ID if successful create, nil otherwise
|
||||
def gitlab_create_group(group_name, api_token)
|
||||
res = send_request_cgi({
|
||||
'method' => 'POST',
|
||||
'uri' => normalize_uri(target_uri.path, '/api/v4/groups'),
|
||||
'ctype' => 'application/json',
|
||||
'headers' => {
|
||||
'PRIVATE-TOKEN' => api_token
|
||||
},
|
||||
'data' => {
|
||||
name: group_name, path: group_name, visibility: 'public'
|
||||
}.to_json
|
||||
})
|
||||
|
||||
raise Msf::Exploit::Remote::HTTP::Gitlab::Error::ClientError.new message: 'Request timed out' unless res
|
||||
|
||||
raise Msf::Exploit::Remote::HTTP::Gitlab::Error::GroupError, "Unable to create group. Unexpected HTTP #{res.code} response." if res.code != 201
|
||||
|
||||
group = JSON.parse(res.body)
|
||||
|
||||
return group if group
|
||||
|
||||
nil
|
||||
end
|
||||
|
||||
# Delete a group
|
||||
#
|
||||
# @return [Bolean,GitLabClientError] True if successful deleted, Msf::Exploit::Remote::HTTP::Gitlab::GitLabClientError otherwise
|
||||
def gitlab_delete_group(group_id, api_token)
|
||||
res = send_request_cgi({
|
||||
'method' => 'DELETE',
|
||||
'uri' => normalize_uri('/api/v4/groups', group_id),
|
||||
'ctype' => 'application/json',
|
||||
'headers' => {
|
||||
'PRIVATE-TOKEN' => api_token
|
||||
}
|
||||
})
|
||||
|
||||
raise Msf::Exploit::Remote::HTTP::Gitlab::Error::ClientError.new message: 'Request timed out' unless res
|
||||
|
||||
raise Msf::Exploit::Remote::HTTP::Gitlab::Error::GroupError, "Unable to delete group. Unexpected HTTP #{res.code} response." if res.code != 202
|
||||
|
||||
true
|
||||
end
|
||||
include Msf::Exploit::Remote::HTTP::Gitlab::Rest::V4::Groups
|
||||
end
|
||||
|
|
|
@ -2,45 +2,5 @@
|
|||
|
||||
# GitLab import mixin
|
||||
module Msf::Exploit::Remote::HTTP::Gitlab::Import
|
||||
# Import a repository from a remote URL
|
||||
#
|
||||
# @return [String,nil] Import ID if successfully enqueued, nil otherwise
|
||||
def gitlab_import_github_repo(group_name:, github_hostname:, api_token:)
|
||||
res = send_request_cgi({
|
||||
'method' => 'POST',
|
||||
'uri' => normalize_uri(target_uri.path, '/api/v4/import/github'),
|
||||
'ctype' => 'application/json',
|
||||
'headers' => {
|
||||
'PRIVATE-TOKEN' => api_token
|
||||
},
|
||||
'data' => {
|
||||
'personal_access_token' => Rex::Text.rand_text_alphanumeric(8),
|
||||
'repo_id' => rand(1000),
|
||||
'target_namespace' => group_name,
|
||||
'new_name' => "gh-import-#{rand(1000)}",
|
||||
'github_hostname' => github_hostname
|
||||
}.to_json
|
||||
})
|
||||
|
||||
raise Msf::Exploit::Remote::HTTP::Gitlab::Error::ClientError.new message: 'Request timed out' unless res
|
||||
|
||||
# 422 is returned if the import failed, but the response body contains the error message
|
||||
if res.code == 422
|
||||
raise Msf::Exploit::Remote::HTTP::Gitlab::Error::ImportError, ((res.get_json_document || {})['errors'] || 'Import failed')
|
||||
end
|
||||
|
||||
# 201 is returned if the import was successfully enqueued
|
||||
unless res.code == 201
|
||||
raise Msf::Exploit::Remote::HTTP::Gitlab::Error::ImportError, ((res.get_json_document || {})['errors'] || 'Import failed')
|
||||
end
|
||||
|
||||
# Example of a successful response body
|
||||
# {"id":54,"name":"gh-import-761","full_path":"/fpXxUqzfQY/gh-import-761","full_name":"fpXxUqzfQY / gh-import-761"}
|
||||
|
||||
body = res.get_json_document
|
||||
|
||||
return body if body
|
||||
|
||||
nil
|
||||
end
|
||||
include Msf::Exploit::Remote::HTTP::Gitlab::Rest::V4::Import
|
||||
end
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
# -*- coding: binary -*-
|
||||
|
||||
module Msf::Exploit::Remote::HTTP::Gitlab::Rest
|
||||
end
|
|
@ -0,0 +1,2 @@
|
|||
module Msf::Exploit::Remote::HTTP::Gitlab::Rest::V4
|
||||
end
|
|
@ -0,0 +1,23 @@
|
|||
# -*- coding: binary -*-
|
||||
|
||||
module Msf::Exploit::Remote::HTTP::Gitlab::Rest::V4::AccessTokens
|
||||
# Revoke a Gitlab access token via the v4 REST api
|
||||
#
|
||||
# @return [nil,GitLabClientError] nil if revoke, Msf::Exploit::Remote::HTTP::Gitlab::GitLabClientError otherwise
|
||||
def gitlab_revoke_personal_access_token(personal_access_token)
|
||||
res = send_request_cgi({
|
||||
'method' => 'DELETE',
|
||||
'uri' => normalize_uri(target_uri.path, '/api/v4/personal_access_tokens/self'),
|
||||
'ctype' => 'application/json',
|
||||
'headers' => {
|
||||
'PRIVATE-TOKEN' => personal_access_token
|
||||
}
|
||||
})
|
||||
|
||||
raise Msf::Exploit::Remote::HTTP::Gitlab::Error::ClientError.new message: 'Request timed out' unless res
|
||||
|
||||
raise Msf::Exploit::Remote::HTTP::Gitlab::Error::ClientError, "Failed to revoke access token. Unexpected HTTP #{res.code} response." unless res.code == 204
|
||||
|
||||
nil
|
||||
end
|
||||
end
|
|
@ -0,0 +1,51 @@
|
|||
# -*- coding: binary -*-
|
||||
|
||||
# GitLab Groups mixin
|
||||
module Msf::Exploit::Remote::HTTP::Gitlab::Rest::V4::Groups
|
||||
# Create a new group
|
||||
#
|
||||
# @return [String,nil] Group ID if successful create, nil otherwise
|
||||
def gitlab_create_group(group_name, api_token)
|
||||
res = send_request_cgi({
|
||||
'method' => 'POST',
|
||||
'uri' => normalize_uri(target_uri.path, '/api/v4/groups'),
|
||||
'ctype' => 'application/json',
|
||||
'headers' => {
|
||||
'PRIVATE-TOKEN' => api_token
|
||||
},
|
||||
'data' => {
|
||||
name: group_name, path: group_name, visibility: 'public'
|
||||
}.to_json
|
||||
})
|
||||
|
||||
raise Msf::Exploit::Remote::HTTP::Gitlab::Error::ClientError.new message: 'Request timed out' unless res
|
||||
|
||||
raise Msf::Exploit::Remote::HTTP::Gitlab::Error::GroupError, "Unable to create group. Unexpected HTTP #{res.code} response." if res.code != 201
|
||||
|
||||
group = JSON.parse(res.body)
|
||||
|
||||
return group if group
|
||||
|
||||
nil
|
||||
end
|
||||
|
||||
# Delete a group
|
||||
#
|
||||
# @return [Bolean,GitLabClientError] True if successful deleted, Msf::Exploit::Remote::HTTP::Gitlab::GitLabClientError otherwise
|
||||
def gitlab_delete_group(group_id, api_token)
|
||||
res = send_request_cgi({
|
||||
'method' => 'DELETE',
|
||||
'uri' => normalize_uri('/api/v4/groups', group_id),
|
||||
'ctype' => 'application/json',
|
||||
'headers' => {
|
||||
'PRIVATE-TOKEN' => api_token
|
||||
}
|
||||
})
|
||||
|
||||
raise Msf::Exploit::Remote::HTTP::Gitlab::Error::ClientError.new message: 'Request timed out' unless res
|
||||
|
||||
raise Msf::Exploit::Remote::HTTP::Gitlab::Error::GroupError, "Unable to delete group. Unexpected HTTP #{res.code} response." if res.code != 202
|
||||
|
||||
true
|
||||
end
|
||||
end
|
|
@ -0,0 +1,45 @@
|
|||
# -*- coding: binary -*-
|
||||
|
||||
module Msf::Exploit::Remote::HTTP::Gitlab::Rest::V4::Import
|
||||
# Import a repository from a remote URL
|
||||
#
|
||||
# @return [String,nil] Import ID if successfully enqueued, nil otherwise
|
||||
def gitlab_import_github_repo(group_name:, github_hostname:, api_token:)
|
||||
res = send_request_cgi({
|
||||
'method' => 'POST',
|
||||
'uri' => normalize_uri(target_uri.path, '/api/v4/import/github'),
|
||||
'ctype' => 'application/json',
|
||||
'headers' => {
|
||||
'PRIVATE-TOKEN' => api_token
|
||||
},
|
||||
'data' => {
|
||||
'personal_access_token' => Rex::Text.rand_text_alphanumeric(8),
|
||||
'repo_id' => rand(1000),
|
||||
'target_namespace' => group_name,
|
||||
'new_name' => "gh-import-#{rand(1000)}",
|
||||
'github_hostname' => github_hostname
|
||||
}.to_json
|
||||
})
|
||||
|
||||
raise Msf::Exploit::Remote::HTTP::Gitlab::Error::ClientError.new message: 'Request timed out' unless res
|
||||
|
||||
# 422 is returned if the import failed, but the response body contains the error message
|
||||
if res.code == 422
|
||||
raise Msf::Exploit::Remote::HTTP::Gitlab::Error::ImportError, ((res.get_json_document || {})['errors'] || 'Import failed')
|
||||
end
|
||||
|
||||
# 201 is returned if the import was successfully enqueued
|
||||
unless res.code == 201
|
||||
raise Msf::Exploit::Remote::HTTP::Gitlab::Error::ImportError, ((res.get_json_document || {})['errors'] || 'Import failed')
|
||||
end
|
||||
|
||||
# Example of a successful response body
|
||||
# {"id":54,"name":"gh-import-761","full_path":"/fpXxUqzfQY/gh-import-761","full_name":"fpXxUqzfQY / gh-import-761"}
|
||||
|
||||
body = res.get_json_document
|
||||
|
||||
return body if body
|
||||
|
||||
nil
|
||||
end
|
||||
end
|
|
@ -0,0 +1,23 @@
|
|||
# -*- coding: binary -*-
|
||||
|
||||
module Msf::Exploit::Remote::HTTP::Gitlab::Rest::V4::Version
|
||||
# Extracts the Gitlab version information from various sources
|
||||
#
|
||||
# @return [String,nil] Gitlab version if found, nil otherwise
|
||||
def gitlab_version
|
||||
res = send_request_cgi({
|
||||
'method' => 'GET',
|
||||
'uri' => normalize_uri(target_uri.path, '/api/v4/version'),
|
||||
'keep_cookies' => true
|
||||
})
|
||||
raise Msf::Exploit::Remote::HTTP::Gitlab::Error::ClientError.new message: 'Request timed out' unless res
|
||||
raise Msf::Exploit::Remote::HTTP::Gitlab::Error::VersionError unless res.code == 200
|
||||
|
||||
body = JSON.parse(res.body)
|
||||
version = body['version'][Regexp.new(Msf::Exploit::Remote::HTTP::Gitlab::GITLAB_VERSION_PATTERN), 1]
|
||||
|
||||
return version if version
|
||||
|
||||
nil
|
||||
end
|
||||
end
|
|
@ -5,23 +5,5 @@ module Msf::Exploit::Remote::HTTP::Gitlab::Version
|
|||
# Used to check if the version is correct: must contain at least one dot
|
||||
GITLAB_VERSION_PATTERN = '(\d+\.\d+(?:\.\d+)*)'.freeze
|
||||
|
||||
# Extracts the Gitlab version information from various sources
|
||||
#
|
||||
# @return [String,nil] Gitlab version if found, nil otherwise
|
||||
def gitlab_version
|
||||
res = send_request_cgi({
|
||||
'method' => 'GET',
|
||||
'uri' => normalize_uri(target_uri.path, '/api/v4/version'),
|
||||
'keep_cookies' => true
|
||||
})
|
||||
raise Msf::Exploit::Remote::HTTP::Gitlab::Error::ClientError.new message: 'Request timed out' unless res
|
||||
raise Msf::Exploit::Remote::HTTP::Gitlab::Error::VersionError unless res.code == 200
|
||||
|
||||
body = JSON.parse(res.body)
|
||||
version = body['version'][Regexp.new(GITLAB_VERSION_PATTERN), 1]
|
||||
|
||||
return version if version
|
||||
|
||||
nil
|
||||
end
|
||||
include Msf::Exploit::Remote::HTTP::Gitlab::Rest::V4::Version
|
||||
end
|
||||
|
|
|
@ -173,7 +173,7 @@ class MetasploitModule < Msf::Exploit::Remote
|
|||
github_hostname: get_uri,
|
||||
api_token: api_token
|
||||
)['id']
|
||||
# binding.pry
|
||||
|
||||
fail_with(Failure::UnexpectedReply, 'Failed to import a repository from GitHub') unless @import_id
|
||||
# wait for the import tasks to finish
|
||||
select(nil, nil, nil, datastore['IMPORT_DELAY'])
|
||||
|
@ -253,5 +253,4 @@ class MetasploitModule < Msf::Exploit::Remote
|
|||
end
|
||||
send_response(cli, data, headers)
|
||||
end
|
||||
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue