GitLab 任意文件讀取漏洞 (CVE-2016-9086) 和任意用戶 token 洩露漏洞

2022-01-26 Seebug漏洞平臺

Author:dawu,LG(知道創宇404安全實驗室)

Data:2016-10-09

0x00 漏洞概述1.漏洞簡介

GitLab 是一個利用Ruby on Rails開發的開源應用程式,實現一個自託管的Git項目倉庫,可通過Web界面進行訪問公開的或者私人項目。近日研究者發現在其多個版本中存在文件讀取漏洞(CVE-2016-9086) 和 任意用戶authentication_token洩漏漏洞,攻擊者可以通過這兩個漏洞來獲取管理員的權限,進而控制所有gitlab項目。

2.漏洞影響任意文件讀取漏洞(CVE-2016-9086):

GitLab CE/EEversions 8.9, 8.10, 8.11, 8.12, and 8.13

任意用戶authentication_token洩露漏洞:

Gitlab CE/EE versions 8.10.3-8.10.5

0x01 漏洞復現1.環境搭建

sudo apt-get install curl openssh-server ca-certificates postfix  curl -s https://packages.gitlab.com/install/repositories/gitlab/gitlab-ce/script.deb.sh | sudo bash  sudo apt-get install gitlab-ce=8.10.3-ce.1  漏洞的復現sudo gitlab-ctl reconfigure  

安裝完成後訪問伺服器80埠即可看到GitLab登錄頁面. 
註:8.9.0-8.13.0版本的gitlab的項目導入功能需要管理員開啟,8.13.0版本之後所有用戶都可以使用導入功能。管理員可以訪問http://domain/admin/application_settings 開啟,開啟之後用任意用戶新建項目的時候,可以在import project from一項中看到gitlab export。

2.漏洞分析任意文件讀取漏洞(CVE-2016-9086)

從8.9.0版本開始,GitLab新增了導入導出項目的功能。 
一個空的gitlab項目導出後結構如下:

其中VERSION文件內容為GitLab的導出模塊的版本,project.json則包含了項目的配置文件。

當我們導入GitLab的導出文件的時候,GitLab會按照如下步驟處理: 1.伺服器根據VERSION文件內容檢測導出文件版本,如果版本符合,則導入。 
2.伺服器根據Project.json文件創建一個新的項目,並將對應的項目文件拷貝到伺服器上對應的位置。

檢測VERSION文件的代碼位於:/lib/gitlab/import_export/version_checker.rb中:

...def check!    version = File.open(version_file, &:readline)  verify_version!(version)
rescue => e    shared.error(e)  false
end  
...
def verify_version!(version)      if Gem::Version.new(version) != Gem::Version.new(Gitlab::ImportExport.version)        raise Gitlab::ImportExport::Error.new("Import version mismatch: Required    
   else        true    end
end  
...

我們可以看到這裡的邏輯是讀取VERSION文件的第一行賦值給變量version,然後檢測verison與當前版本是否相同,相同返回true,不相同則返回錯誤信息(錯誤信息中包括變量version的值). 於是漏洞發現者Jobert Abma巧妙的使用了軟連結來達到讀取任意文件的目的。首先,我們給VERSION文件加上軟連結並重新打包。

ln -sf /etc/passwd VERSION  tar zcf change_version.tar.gz ./  

這樣,讀取VERSION文件的時候伺服器就會根據軟連結讀取到/etc/passwd的第一行內容並賦值給version。但是由於version與當前版本不相同,所以會輸出version的值,也就是/etc/passwd第一行的內容。

訪問之前搭建好的GitLab伺服器,創建一個新的項目,填寫完項目名稱後在Import project from一欄中選擇GitLab export,上傳我們修改後的導入包,然後就可以看到/etc/passwd文件第一行

但是,如果只讀取任意文件的第一行,能做的事情還是太少了。漏洞發現者顯然不滿足這一結果,他繼續找了下去. 
讀取Project.json這一配置文件的代碼位於:/lib/gitlab/import_export/project_tree_restorer.rb中:

...
def restore    json = IO.read(@path)  tree_hash = ActiveSupport::JSON.decode(json)  project_members = tree_hash.delete('project_members')  ActiveRecord::Base.no_touching do    create_relations  
end
rescue => e    shared.error(e)  false
end  
...

在這裡,我們可以再次使用軟連結使變量json獲取到任意文件的內容,但是由於獲取的文件不是json格式,無法decode,導致異常拋出,最終在前端顯示出任意文件的內容。 添加軟連結並打包:

ln -sf /etc/passwd project.json  tar zcf change_version.tar.gz ./  

上傳導出包,頁面上顯示的結果:

任意用戶authentication_token洩露漏洞復現步驟為:

1.註冊一個普通用戶,創建一個新的項目 
2.在項目的member選項中,添加管理員到項目中。

3.點擊edit project,找到Export project部分,點擊Export project,等待幾分鐘去查看註冊郵箱收到的下載地址或者刷新頁面,點擊Download export下載導出包。

4.導出包的project.json中已經含有了管理員的authentication_token。

得到authentication_token之後我們就可以通過api做管理員可以做的事情了,比如查看管理員所在的項目:

分析原因:

我們在\app\controllers\projects_controller.rb中找到了export函數,這個函數被用來導出項目文件。

 def export    
   @project.add_export_job(current_user: current_user)    redirect_to(      edit_project_path(@project),      notice: "Project export started. A download link will be sent by email."    )  end

往下跟add_export_job(),在\app\models\project.rb中:

 def add_export_job(current_user:)    job_id = ProjectExportWorker.perform_async(current_user.id, self.id)    if job_id      
     Rails.logger.info "Export job started for project ID    
   else      Rails.logger.error "Export job failed to start for project ID    
   end  end

繼續到\app\workers\project_export_worker.rb文件的ProjectExportWorker.perform_async():

class ProjectExportWorker    include Sidekiq::Worker  sidekiq_options queue: :gitlab_shell, retry: 3  def perform(current_user_id, project_id)    current_user = User.find(current_user_id)    project = Project.find(project_id)    ::Projects::ImportExport::ExportService.new(project, current_user).execute  
 end
end  

這裡我們可以看到current獲取的是User.find(current_user_id)的內容,然後調用::Projects::ImportExport::ExportService.new(project, current_user).execute 由於筆者之前沒有接觸過ruby,這裡只好採用gitlab-rails console來找到User.find()的值。可以看到,在User.find()中,存在authentication_token的值。

跟到\app\services\project\import_export\export_service.rb,這裡執行version_saver, avatar_saver, project_tree_saver, uploads_saver, repo_saver, wiki_repo_saver這五個函數來寫各種導出文件,其中project_tree_saver()負責導出project.json

module Projects    module ImportExport    class ExportService < BaseService      def execute(_options = {})        @shared = Gitlab::ImportExport::Shared.new(relative_path: File.join(project.path_with_namespace, 'work'))        save_all      
     end      private      
     
     def save_all        
       if [version_saver, avatar_saver, project_tree_saver, uploads_saver, repo_saver, wiki_repo_saver].all?(&:save)          Gitlab::ImportExport::Saver.save(project: project, shared: @shared)          notify_success        
       else          cleanup_and_notify        
       end      end      def version_saver      
     ...    end  end
end  

跳過之後的幾個繁瑣的調用之後,執行了lib/gitlab/import_export/json_hash_builder.rb中的create_model_value函數。

   
   
   
   
   
   
 def create_model_value(current_key, value, json_config_hash)    parsed_hash = { include: value }    parse_hash(value, parsed_hash)    json_config_hash[current_key] = parsed_hash  
 end    
   
   
   
 def parse_hash(value, parsed_hash)    @attributes_finder.parse(value) do |hash|      parsed_hash = { include: hash_or_merge(value, hash) }    end  end

這裡出現了邏輯問題,由於parsed_hash這個變量不是全局變量,所以create_model_value()中執行parse_hash()時,parse_hash()中的parsed_hash被改變,但是create_model_value()函數中的parsed_hash不會變,這就造成了parse_hash()這個函數執行後create_model_value()中parsed_hash這個值並沒有改變。因此最後導出的文件包含了authentication_token。

我們在gitlab-rails console裡展示了這兩者的區別。當value=user的時候,parsed_hash={:include=>:user},輸出的結果如同圖中的user.as_json(),會將所有內容輸出,包括authentication_token。當parsed_hash為經過parse_hash()處理後的{:include=>{:user=>{:only=>[:id, :email, :username]}}}時,輸出結果與user.as_json(only: [:id, :email, :username])相同。

後續RCE方式的探討

在hackone的兩個報告中,漏洞發現者都提到了leads to RCE,筆者嘗試去實現這一點。由於GitLab源碼在gitlab.com上,所以當獲取了GitLab的管理員權限後,我們可以通過authentication_token修改GitLab項目的源碼,留下自己的後門。 為了重現這種情況,我們在本地新建一個新的項目去通過authentication_token和GitLab api來修改項目文件。

用root帳戶創建一個項目:test_rce,其中README.md的內容為created by root接下來,我們要用gitlab的api來修改它。首先,根據projects的api找到test_rce項目對應的id,這裡是18

curl -H "PRIVATE-TOKEN: wTPMMapDwpfkKfNws7xp" "http://domain/api/v3/projects"  

我們再根據api讀取一下文件

curl -H "PRIVATE-TOKEN: wTPMMapDwpfkKfNws7xp" "http://domain/api/v3/projects/18/repository/files?file_path=README.md&ref=master"  

這裡,content為Y3JlYXRlZCBieSByb290,這是文件內容被base64加密後的結果,解密一下就可以看到created by root

根據api的要求,我們通過PUT數據來修改文件,將README.md修改為change by notroot。 當我們再讀一次,content內容為:Y2hhbmdlIGJ5IG5vdHJvb3Q=,解碼之後就是change by notroot

不得不說,筆者所實現的這種方式攻擊時間跨度很長,能否執行命令取決於開發者下一次更新的時間,這也是這種方法的缺點之一。

0x02 官方修複分析任意文件讀取漏洞(CVE-2016-9086)修複分析

我們可以看到,官方先移除了導入包裡的軟連接,其次,讀取VERSION的內容和project.json的內容出錯後將內容輸出到日誌裡而非返回到前端。

任意用戶authentication_token洩露漏洞修複分析

官方讓json_config_hash[current_key]獲取到parse_hash()處理後的值。

0x03 參考

相關焦點

  • 「預警信息」關於VMwarevCenter任意文件讀取高危漏洞的預警通報
    近日,我中心技術支持單位通報:VMware vCenter特定版本存在任意文件讀取高危漏洞,攻擊者可在目標伺服器上讀取任意文件。一、漏洞情況VMware vCenter 伺服器是一種高級伺服器管理軟體,提供一個用於控制 VMware vSphere 環境的集中式平臺,幫助用戶獲取集中式可見性、簡單高效的規模化管理,從而在整個混合雲中自動部署和交付虛擬基礎架構。
  • PHP任意文件上傳漏洞(CVE-2015-2348)
    任意文件上傳漏洞(CVE-2015-2348)。 在上傳文件的時候只判斷文件名是合法的文件名就斷定這個文件不是惡意文件,這確實會導致其他安全問題。並且在這種情況下,在你自己的文件中檢查漏洞很不現實,因為這個漏洞可以繞過你對文件名後綴、文件類型(Content-Type)、Mime type、文件大小等的檢查,所以僅僅依靠這些檢查是救不了你的。
  • 【漏洞通告】Apache Druid LoadData文件讀取漏洞 CVE-2021-36749
    >漏洞類型 : 文件讀取利用條件 :1、用戶認證:否2、觸發方式:遠程3、前置條件:默認配置綜合評價 : <綜合評定利用難度>:容易,無需授權即可文件讀取。Druid 還支持根據時間戳對數據進行預聚合攝入和聚合分析,因此也有用戶經常在有時序數據處理分析的場景中使用。近日,深信服安全團隊監測到一則Apache Druid組件存在文件讀取漏洞的信息,漏洞編號:CVE-2021-36749,漏洞威脅等級:中危。
  • 【php安全】--文件讀取漏洞
    簡介:如果是任意文件讀取,可以直接讀取資料庫配置文件。
  • 路由器漏洞挖掘之 DIR-805L 越權文件讀取漏洞分析
    本文在復現 DIR-805L 任意文件讀取漏洞時,將會比較詳細的分析一下用於 cgi 處理的 phpcgi_main 函數其中的一些功能。在逆向 cgibin 二進位文件時,常常會遇到一些用於解析 http 請求的函數,在分析時經常對這些函數的用法不太清楚。總是雲裡霧裡的,所以這裡對這些函數做一個比較細緻的總結,希望對同樣在學這塊的朋友們一點啟發吧,也算是達到拋磚引玉的目的吧。
  • Python代碼審計實戰案例總結之CRLF和任意文件讀取
    目前Python代碼審計思路,呈現分散和多樣的趨勢。Python微薄研發經驗以及結合實際遇到的思路和技巧進行總結,以便於朋友們的學習和參考。CRLF和任意文件讀取的審計實戰CRLF 審計實戰CRLF的問題經常會出現在Python的模塊之中,曾經有案例說明httplib模塊、urllib模塊等存在CRLF問題。
  • Android DropBox SDK漏洞(CVE-2014-8889)分析
    在許多方面,包括訪問控制功能的app與服務之間的互操作總是具有挑戰性的,為了解決訪問控制來來的挑戰,OAuth1和2等授權協議陸續被提出,它們可以安全地授予app訪問特定服務中個人數據的權限,而又不洩露用戶的個人憑據。為便於開發,這些服務通常為app提供一個框架或SDK,使app能夠和服務進行通信。
  • CVE-2018-19788:UID大於INT_MAX的Linux用戶任意代碼執行漏洞
    Linux作業系統中UID值大於2147483647的低權限帳戶可以未授權執行任意systemctl命令。該漏洞存在於PolicyKit(polkit)中,PolicyKit是類Unix作業系統中定義策略、處理系統範圍內權限和提供給非特權進程與特權進程通信方式的應用級工具集,比如sudo。
  • 關於ThinkPHP 6.0存在任意文件寫入高危漏洞的預警通報
    近日,奇安信補天漏洞響應平臺收到ThinkPHP 6.0任意文件創建漏洞。該漏洞源於ThinkPHP 6.0的某個邏輯漏洞,成功利用此漏洞的攻擊者可以實現「任意」文件創建,在特殊場景下可能會導致GetShell。
  • Windows VBScript引擎遠程執行代碼漏洞 CVE-2018-8174分析與利用
    VBScript引擎處理內存中對象的方式中存在一個遠程執行代碼漏洞。該漏洞可能以一種攻擊者可以在當前用戶的上下文中執行任意代碼的方式來破壞內存。成功利用此漏洞的攻擊者可以獲得與當前用戶相同的用戶權限。如果當前用戶使用管理用戶權限登錄,則成功利用此漏洞的攻擊者可以控制受影響的系統。然後攻擊者可以安裝程序; 查看,更改或刪除數據; 或創建具有完全用戶權限的新帳戶。
  • 曝QQ郵箱存在安全漏洞 可隨意登錄任意帳號-曝QQ郵箱存在安全漏洞...
    今天,有一位名為「草尚飛」的用戶在微博上反映,用手機登錄QQ郵箱時,隨意輸入一個QQ郵箱的帳號和密碼,就可以登錄成功。這是不是意味著自己的郵箱有可能被別人登錄?用戶表示了對於郵箱安全的擔憂。對此,小編進行了測試,發現確實如網友所言,用一個隨意一個帳號和密碼的組合,實現成功登錄,這或許暴露了QQ郵箱在安全方面的一個重要漏洞。
  • Web安全之文件包含漏洞
    2、漏洞產生原因程序沒有對文件的來源進行嚴格的審查,可以被用戶控制,包含其他惡意文件,導致了執行了非預期的代碼,也就是程式設計師在編寫代碼的時候觸犯的邏輯性的錯誤,就可能會導致文件讀取漏洞和其它類型的漏洞PHP中文件包含函數有以下四種:require() require_once() include()
  • 從任意文件讀取到拿webshell
    對於任意文件讀取漏洞讀取一個不存在的文件,確定讀取不存在文件時的狀態,標誌性文件可隨意拓展,注意選取標誌性文件時選取讀取權限要求最低的文件/的數量,直到讀取到web.xml 文件,一般不會超過 10 個路徑深度。註:涉及到上傳文件目錄和 web 目錄分離的情況無法讀取到 web.xml 可考慮其他參照文件,多開腦洞就行
  • 重大漏洞 攜程被曝洩露用戶銀行卡信息
    3月22日,烏雲漏洞平臺發布消息稱,攜程系統存技術漏洞,這個漏洞可能導致用戶個人信息、銀行卡信息等遭到洩漏。消息發布的當晚,攜程表示已進行技術排查和修復。並稱如用戶因此產生損失,攜程將會賠償。同時因為保存支付日誌的伺服器未做校嚴格的基線安全配置,存在目錄遍歷漏洞,導致所有支付過程中的調試信息可被任意駭客讀取。這些信息包括持卡人姓名、身份證、銀行卡類別、銀行卡號、CVV碼,6位Bin。● 攜程方面    攜程方面得知此消息之後,相關的技術人員馬上進行漏洞的排查和補救工作,目前漏洞已經得到了修復。
  • AMD錄屏軟體「PlaysTV」爆高危漏洞 用戶文檔可被任意篡改
    近日,騰訊電腦管家安全專家發現AMD顯卡驅動程序包中所包含的錄屏軟體「PlaysTV」存在高危漏洞「CVE-2018-6547」,影響「PlaysTV」1.27.5及之前所有版本,不法黑客可利用該漏洞篡改用戶電腦文件狀態或遠程共享其文件,甚至操控用戶電腦執行惡意行為。目前,騰訊電腦管家已實時攔截該漏洞攻擊,並建議用戶儘快升級AMD顯卡驅動程序至最新版本。
  • SRC邏輯漏洞挖掘詳解以及思路和技巧
    ,有很強的邏輯思維能力,所以下面主要描述一下ZZCMS8.1中註冊、登錄和密碼找回出現的漏洞邏輯,再儘量多和全的收集整理相關場景。4.過程5代表攻擊者safedog在獲得受害者victim的Cookie後,利用受害者victim的Cookie與PHPMyWind網站的邏輯漏洞點進行密碼重置攻擊。反射型XSS攻擊者搭建可接收受害者Cookie的PHP網站;該PHP網站由「ReflectiveXSS.js」「ReflectiveXSS.php」和「cookie.txt」這3個文件構成。
  • SUMAP網絡空間測繪|2021年CVE漏洞趨勢安全分析報告
    同時攻擊者在面向全網攻擊,既包括傳統攻擊方式WEB攻擊、緩衝區溢出攻擊、資料庫攻擊,也涵蓋了新型攻擊——重點針對物聯網設備和工控設備層面的攻擊,現階段也越發的頻繁。 對於今天的網際網路安全我們更需要通過模型監測方式來持續觀察漏洞趨勢和影響範圍,才能持續應對漏洞爆發之後的安全趨勢分析評估。
  • 【經典回顧系列】 一步一步教你漏洞挖掘之Windows SMB Ghost CVE-2020-0796(二)
    利用NtQuerySystemInformation實現進程token洩露Easy Local Windows Kernel Exploitation (cesarcer)https://media.blackhat.com/bh-us-12/Briefings/Cerrudo/BH_US_12_Cerrudo_Windows_Kernel_WP.pdfAbusing
  • PHPMailer 任意文件讀取漏洞
    ——公司:安恆信息崗位:Web安全 安全研究員部門:戰略支援部薪資:13-30K工作年限:1年+工作地點:杭州(總部)、廣州、成都、上海、北京工作環境:一座大廈,健身場所,醫師,帥哥,美女,高級食堂…【崗位職責】1.定期面向部門、全公司技術分享;2.前沿攻防技術研究、跟蹤國內外安全領域的安全動態、漏洞披露並落地沉澱
  • 記一次.Net代碼審計-通過machineKey偽造任意用戶身份
    0x02 場景看了沒多久發現一個任意文件下載的漏洞,SQL注入,文件上傳任意代碼執行也存在.但是只有任意文件文件下載是不需要驗證的,其他漏洞都需要驗證身份後才能利用成功,如何才能獲取一個身份擴大利用面呢?仔細查看登錄邏輯代碼並不存在sql注入,系統支持中文,數字,字母格式的用戶名,弱口令也是不好搞的,況且也未發現敏感信息洩露。等等,不是還有任意文件下載嗎?