Skip to content
KitploitKITPLOIT
ToolsExploitsBlog
Log in
Einreichen
ToolsExploitsBlog
Einreichen

Hacking-, PenTest- und Cybersicherheits-Tools für Ihr Sicherheitsarsenal!

Kitploit ist ein Verzeichnis von Hacking-, Cybersicherheits- und Pentesting-Tools. Entdecken Sie die neuesten Projekt-Updates, um Schwachstellen zu finden, Systeme zu analysieren, Tests zu automatisieren und Ihre Sicherheit zu stärken.

FeedsKontaktDatenschutz© 2026 Kitploit

Tool-Verzeichnis

Kategorien

Alle Kategorien anzeigen
Loading categories
Gitlab-RCE — CVE-2021-22192 | Kitploit
Tools/GitHubGitHub/petrusviet/gitlab-rce
SchwachstellenanalyseCode-AnalyseExploitationWebanwendungs-ExploitationPapers & ForschungLernen & Bildung
GitHubpetrusviet/gitlab-rce

Gitlab-RCE

CVE-2021-22192

Repository anzeigen
12311vor 5 JahrenNoch nicht geprüft

Beliebteste

Alle anzeigen →

Entdecken Sie die meistgenutzten Tools unserer Community.

Alle Tools erkunden

Durchsuchen Sie unsere Tool-Sammlung

Alle Tools anzeigen →
Teilen

Analyse der RCE-Schwachstelle in Gitlab (CVE-2021–22192)

I) Aufbau

  • Dieser Fehler tritt in GitLab Community Edition (CE) und Enterprise Edition (EE) in den Versionen (>=13.2, <13.7.9), (>=13.8, <13.8.6) und (>=13.9, <13.9.4) auf.
  • Du kannst der Anleitung von lyy289065406 folgen, um die Umgebung aufzubauen.

II) Analyse

Als ich mit der Analyse dieses Fehlers begann, hatte ich nur einige wertvolle Informationen von lyy289065406, die mir halfen, das Kernproblem dieses Bugs zu verstehen. Es schien, dass der Fehler in der gem kramdown (<= 2.3.0) liegt, also beschäftigte ich mich zuerst mit kramdown.

1. Kramdown

Wir können den Patch von kramdown prüfen und sehen den Unterschied in der Funktion formatter_class im Modul Kramdown::Converter::SyntaxHighlighter::Rouge.

::Rouge::Formatters.const_get(formatter) wurde zu ::Rouge::Formatters.const_get(formatter, false) geändert.

Die Methode const_get wird von der Klasse Object geerbt und kann Konstanten abrufen. Sie kann sogar Klassen zurückgeben, die zuvor deklariert wurden und die sie finden kann. Der Unterschied besteht hier nur im zusätzlichen Parameter false. Durch das Hinzufügen von false kann const_get keine Konstanten aus übergeordneten Klassen oder Modulen mehr abrufen.

Besonders ist außerdem, dass in der Funktion self.call formatter_class aufgerufen und anschließend new(opts) ausgeführt wird. Das bedeutet, dass die über const_get ermittelte Methode über den Konstruktor initialisiert wird.

def self.call(converter, text, lang, type, call_opts)
      opts = options(converter, type)
      call_opts[:default_lang] = opts[:default_lang]
      return nil unless lang || opts[:default_lang] || opts[:guess_lang]

      lexer = ::Rouge::Lexer.find_fancy(lang || opts[:default_lang], text)
      return nil if opts[:disable] || !lexer || (lexer.tag == "plaintext" && !opts[:guess_lang])

      opts[:css_class] ||= 'highlight' # For backward compatibility when using Rouge 2.0
      formatter = formatter_class(opts).new(opts)
      formatter.format(lexer.lex(text))
    end

Wow, wow. Wie kann man das also ausnutzen???

Mithilfe von Kramdown:Options können wir die Funktion Kramdown::Converter::SyntaxHighlighter::Rouge.call aufrufen.

{::options auto_ids="false" footnote_nr="5" syntax_highlighter="rouge" syntax_highlighter_opts="{formatter: CSV, line_numbers: true\}" /}

Außerdem sehen wir, dass im Modul Kramdown:Options die Funktion simple_hash_validator YAML.safe_load(val) aufruft. Damit können wir auch eine YML-Datei konfigurieren, um die gewünschte Payload an Kramdown::Converter::SyntaxHighlighter::Rouge zu übergeben.

def self.simple_hash_validator(val, name)
      if String === val
        begin
          val = YAML.safe_load(val)
        rescue RuntimeError, ArgumentError, SyntaxError
          raise Kramdown::Error, "Invalid YAML value for option #{name}"
        end
      end
      raise Kramdown::Error, "Invalid type #{val.class} for option #{name}" unless Hash === val
      val
    end
  • Kramdown wird von Jekyll, GitLab Pages, GitHub Pages und Thredd Forum verwendet. Deshalb habe ich beschlossen, es zuerst mit Jekyll auszuprobieren.

2. jekyll

Zuerst muss ich Jekyll aufsetzen:

  • Jekyll installieren
gem install jekyll
  • Jekyll-Seite mit dem Namen jekyllTest erstellen
jekyll new jekyllTest
  • Die Datei Gemfile.lock bearbeiten, um die kramdown-Version auf <= 2.3.0 zu setzen
cd jekyllTest

Datei Gemfile.lock


...
kramdown (2.3.0)
...

  • Seite installieren
 bundle install

Damit haben wir eine Jekyll-Seite erstellt. Nun können wir eine Payload einfügen, um zu sehen, ob Kramdown::Converter::SyntaxHighlighter::Rouge.call tatsächlich eine Methode aufrufen kann.

Wir können in die Datei ./_config.yml Folgendes einfügen:

kramdown:
  syntax_highlighter: rouge
  syntax_highlighter_opts:
    formatter: CSV

Oder ein kramdown-Dokument verwenden, indem wir die Payload in ./_posts/*.markdown einfügen.

{::options auto_ids="false" footnote_nr="5" syntax_highlighter="rouge" syntax_highlighter_opts="{formatter: CSV, line_numbers: true\}" /}

~~~ ruby
def what?
  42
end
~~~

Hier verwende ich die zweite Methode =)))))

  • Wir deployen die Jekyll-Seite
 bundle exec jekyll serve

Möglicherweise tritt der Fehler "require': cannot load such file -- webrick (LoadError)" auf; du musst gem "webrick" zur Gemfile hinzufügen

  • Wir sehen die Fehlermeldung private method 'format' called for #<CSV io_type:Hash encoding:UTF-8 lineno:0 col_sep: Das zeigt, dass die Klasse CSV aufgerufen wurde.

Als Nächstes muss ich festlegen, welche Methode gewählt werden soll, damit der Konstruktoraufruf eine RCE auslösen kann?

Laut einem Analyseartikel zu CVE-2020-10518, der den kramdown-Fehler nutzt, um eine RCE auf GitHub auszulösen, ziele ich auf die Klasse Hoosegow:

  • Wir sehen, dass in der Funktion initialize von Hoosegow load_inmate_methods aufgerufen wird.
def initialize(options = {})
    options         = options.dup
    @no_proxy       = options.delete(:no_proxy)
    @inmate_dir     = options.delete(:inmate_dir) || '/hoosegow/inmate'
    @image_name     = options.delete(:image_name)
    @ruby_version   = options.delete(:ruby_version) || RUBY_VERSION
    @docker_options = options
    load_inmate_methods
  • In load_inmate_methods sehen wir, dass require inmate_file aufgerufen wird.
 def load_inmate_methods
    inmate_file = File.join @inmate_dir, 'inmate.rb'

    unless File.exist?(inmate_file)
      raise Hoosegow::InmateImportError, "inmate file doesn't exist"
    end

    require inmate_file

    unless Hoosegow.const_defined?(:Inmate) && Hoosegow::Inmate.is_a?(Module)
      raise Hoosegow::InmateImportError,
        "inmate file doesn't define Hoosegow::Inmate"
    end

    if no_proxy?
      self.extend Hoosegow::Inmate
    else
      inmate_methods = Hoosegow::Inmate.instance_methods
      inmate_methods.each do |name|
        define_singleton_method name do |*args, &block|
          proxy_send name, args, &block
        end
      end
    end
  end
  • Aber inmate_file wird durch Verkettung von @inmate_dir mit 'inmate.rb' erzeugt. Wenn wir diese Klasse aufrufen und den Parameter inmate_dir auf den Pfad zu unserer Payload-Datei setzen können, würde dann nicht hier eine RCE auftreten?

  • Ich führe ein Skript im Pfad der Jekyll-Seite aus, um die definierten Methoden zu überprüfen:

require "bundler"
Bundler.require

methods = []
ObjectSpace.each_object(Class) {|ob| methods << ( {ob: ob }) if ob.name =~ /\A[[:upper:]][[:alnum:]_]*\z/ }
 
methods.each do |m|
  begin
    puts "trying #{m[:ob]}"
    m[:ob].new({a:1, b:2})
    puts "worked\n\n"
  rescue ArgumentError
      puts "nope\n\n"
  rescue NoMethodError
      puts "nope\n\n"
  rescue => e
      p e
      puts "maybe\n\n"
  end
  • Leider gibt es keine Klasse mit dem Namen Hoosegow, selbst als ich den Skriptabbruch umgangen habe, indem ich die Bedingung ob.name == "Hoosegow" verwendet habe.
require "bundler"
Bundler.require
  
methods = []
ObjectSpace.each_object(Class) {|ob| methods << ( {ob: ob }) if ob.name == "Hoosegow"  }

...
  • Es stellte sich heraus, dass die Klasse Hoosegow in meinem Klassenpfad nicht deklariert war. Ich fügte gem "hoosegow" zur Gemfile hinzu, und das Skript fand diese Klasse. [Hehehe]

  • Als Nächstes versuche ich, Hoosegow über kramdown aufzurufen.

Tool herunterladen