Skip to content

Commit

Permalink
add 2018-12-12-CVE-2018-18649-Gitlab-RCE
Browse files Browse the repository at this point in the history
  • Loading branch information
asakawa committed Dec 12, 2018
1 parent 5310ac7 commit ede02ef
Show file tree
Hide file tree
Showing 2 changed files with 103 additions and 0 deletions.
103 changes: 103 additions & 0 deletions _posts/2018-12-12-CVE-2018-18649-Gitlab-RCE.markdown
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
---
layout: post
title: "Second bite on GitLab, and some interesting Ruby functions/features"
date: 2018-12-12 15:34:11 +0800
categories: jekyll update
---

# Brief
It's been a while since I wrote something in this blog last time. I just posted
something about several bugs I found several months ago in GitHub Pages and
GitHub Enterprise. Go check them out if you are interested in some more examples
of incorrect path sanitizing and symbolic links in real world softwares!

But today I'm not going to talk about more of those. I'm going introduce some
recent findings about Ruby and how did a find an RCE bug in GitLab.
([CVE-2018-18649](https://about.gitlab.com/2018/10/29/security-release-gitlab-11-dot-4-dot-3-released/))

# Ruby and GitLab
I wrote Ruby a lot when I was still in university. I used Ruby almost everywhere
I could use and even once submitted an assignment of my Operating System course
about threads and processes. However, after I didn't have much time to continue
on the cool stuff with Ruby and focused on something else. :(

Recently, the experiences during the code auditing of GitLab, GitHub and several
other cool Ruby projects recalls me the best days of learning Ruby and feels me
like I'm designing the software and refining the code snippets with the developers.

As many people say, Ruby is an extremely flexible language and this flexibility
brings us elegant implementations, the freedom of creating DSL and etc. However
the flexibility also brings unnoticeable bugs. Here I'm going to show some code
snippets existed in GitLab.

## Duck Typing

> If it walks like a duck, swims like a duck, and quacks like a duck, then it probably is a duck.
GitLab uses [Grape](https://github.com/ruby-grape/grape) to create their APIs,
for example, the following API is used to upload attachments to the wiki of a
project.

``` ruby
params do
requires :file, type: File, desc: 'The attachment file to be uploaded'
optional :branch, type: String, desc: 'The name of the branch'
end
post ":id/wikis/attachments", requirements: API::PROJECT_ENDPOINT_REQUIREMENTS do
authorize! :create_wiki, user_project

result = ::Wikis::CreateAttachmentService.new(user_project,
current_user,
commit_params(declared_params(include_missing: false))).execute
...
end
```

Normally, Rack intercepts file uploading requests and sets `params[key][:tempfile]`
and `params[key][:filename]` to the temporary path of the uploaded file and the
original filename. So GitLab reads the content of the temp file and saves it
afterwards.

``` ruby
def commit_params(attrs)
{
file_name: attrs[:file][:filename],
file_content: File.read(attrs[:file][:tempfile]),
branch_name: attrs[:branch]
}
end
```

At the same time, grape has a simple validation for `type: File`:

``` ruby
def value_coerced?(value)
# Rack::Request creates a Hash with filename,
# content type and an IO object. Do a bit of basic
# duck-typing.
value.is_a?(::Hash) && value.key?(:tempfile)
end
```

Well, it's not really duck-typing here. But the comments of the developer
reminds me this and it's surely thinking about duck-typing when it was
implementing this function.

Unfortunately, only duck quacking is not enough. A key named `:tempfile` exists
in the `params[:file]` hash doesn't really mean `params[:file]` is really a
uploaded file as expected.

Sending a simple POST request, we can easily smuggle our duck-like bird to pass this
duck typing check by setting `file[tempfile]` in the form data.

``` shell
curl -d "file[tempfile]=/etc/passwd&file[filename]=123" http://host:port
```

So, our bird can pass the inspection and tell us anything within a GitLab instance.

![2018-12-12-CVE-2018-18649-Gitlab-RCE_1](/assets/2018-12-12-CVE-2018-18649-Gitlab-RCE_1.png)

## TBD
I'll leave the command execution part to my next post, where I'll introduce
another interesting flexibility in Ruby.
Binary file added assets/2018-12-12-CVE-2018-18649-Gitlab-RCE_1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit ede02ef

Please sign in to comment.