Module: Msf::Exploit::Remote::HTTP::Gitlab::Version

Includes:
Rest::V4::Version
Included in:
Msf::Exploit::Remote::HTTP::Gitlab
Defined in:
lib/msf/core/exploit/remote/http/gitlab/version.rb

Overview

GitLab version mixin

Constant Summary collapse

GITLAB_VERSION_PATTERN =

Used to check if the version is correct: must contain at least one dot

'(\d+\.\d+(?:\.\d+)*)'.freeze
GITLAB_CSS_PATTERN =

CSS-based filename fingerprinting

'<link rel="stylesheet"(?: media="[a-z]+")? href="/assets/application-([a-z0-9]+)[.]css"'.freeze
GITLAB_CSS_MAP =

Map of CSS filenames to GitLab versions, loaded from data/gitlab_versions.json File generated by tools/dev/update_gitlab_versions.rb

JSON.parse(File.read(File.join(Msf::Config.data_directory, 'gitlab_versions.json'))).freeze

Instance Method Summary collapse

Methods included from Rest::V4::Version

#gitlab_version_rest

Instance Method Details

#convert_to_rex_version_range(version) ⇒ [Rex::Version(low_version), Rex::Version(high_version)]?

Parses the Gitlab version information and ensures an array of two Rex::Version objects are returned in the following format: [Rex::Version(low_version), Rex::Version(high_version)] even if low_version and high_version are the same.

Returns:



22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
# File 'lib/msf/core/exploit/remote/http/gitlab/version.rb', line 22

def convert_to_rex_version_range(version)
  return nil unless version

  if version.is_a?(Array) && version.length == 2
    low_version, high_version = version
    low_version = Rex::Version.new(low_version)
    high_version = Rex::Version.new(high_version)
    report_gitlab_service("#{low_version} - #{high_version}")
    [low_version, high_version]
  else
    version = Rex::Version.new(version)
    report_gitlab_service(version.to_s)
    [version, version]
  end
end

#gitlab_version[Rex::Version(low_version), Rex::Version(high_version)]?

Extracts the Gitlab version information and returns a version range.

Returns:



41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
# File 'lib/msf/core/exploit/remote/http/gitlab/version.rb', line 41

def gitlab_version
  version = gitlab_version_css(normalize_uri(target_uri.path))
  return convert_to_rex_version_range(version) if version

  begin
    version = gitlab_version_rest
    return convert_to_rex_version_range(version) if version
  rescue Msf::Exploit::Remote::HTTP::Gitlab::Error::VersionError
    # ignore silently instead of causing the module to fail if the REST API is not available or does not return version information in the expected format
  end

  version = gitlab_version_help_commit(normalize_uri(target_uri.path))
  begin
    return convert_to_rex_version_range(version) if version
  rescue StandardError
    print_warning("Unable to process version #{version} from help page (possible commit hash)")
  end

  nil
end

#gitlab_version_css(url) ⇒ String?

Checks the name of a CSS file to fingerprint the version

Parameters:

  • url, (String)

    the url of the Gitlab instance

Returns:

  • (String, nil)

    Gitlab version if found, nil otherwise



95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
# File 'lib/msf/core/exploit/remote/http/gitlab/version.rb', line 95

def gitlab_version_css(url)
  res = send_request_cgi!(
    'method' => 'GET',
    'uri' => url
  )
  unless res
    return nil
  end

  match = res.body.match(GITLAB_CSS_PATTERN)
  unless match
    return nil
  end

  version = GITLAB_CSS_MAP.fetch(match[1], nil)
  if version
    GITLAB_CSS_MAP.fetch(match[1], nil)
  else
    print_warning("The GITLAB_CSS_PATTERN was found in the response body but the hash found: #{match[1]} does not have a corresponding version in the GITLAB_CSS_MAP")
    nil
  end
end

#gitlab_version_help_commit(url) ⇒ String?

Get the commit hash via the ‘gon.revision` javascript variable

Parameters:

  • url, (String)

    the url of the Gitlab instance

Returns:

  • (String, nil)

    Gitlab commit hash if found, nil otherwise



123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
# File 'lib/msf/core/exploit/remote/http/gitlab/version.rb', line 123

def gitlab_version_help_commit(url)
  res = send_request_cgi!(
    'method' => 'GET',
    'uri' => normalize_uri(url, '/help')
  )
  unless res
    return nil
  end

  match = res.body.match(';gon[.]revision="([0-9a-f]+)";')
  unless match
    return nil
  end

  return match[1]
end

#report_gitlab_service(version_info) ⇒ void

This method returns an undefined value.

Report GitLab as an application service with HTTP(S) and TCP parent services.

Parameters:

  • version (String, Array<String>)

    GitLab version value or range



67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
# File 'lib/msf/core/exploit/remote/http/gitlab/version.rb', line 67

def report_gitlab_service(version_info)
  report_service(
    host: rhost,
    port: rport,
    proto: 'tcp',
    name: 'GitLab',
    info: "GitLab #{version_info}",
    parents: {
      name: ssl ? 'https' : 'http',
      host: rhost,
      port: rport,
      proto: 'tcp',
      parents: {
        name: 'tcp',
        host: rhost,
        port: rport,
        proto: 'tcp',
        parents: nil
      }
    }
  )
end