-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
add 2018-12-12-CVE-2018-18649-Gitlab-RCE
- Loading branch information
asakawa
committed
Dec 12, 2018
1 parent
5310ac7
commit ede02ef
Showing
2 changed files
with
103 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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. |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.