Command Injection via Data taken from GCloud API and ENV
HackerOne report #492635 by mehmet
on 2019-02-07, assigned to dappelt
:
Hello,
During code-review I've seen following function at qa/qa/service/kubernetes_cluster.rb
.
def attempt_login_with_env_vars
puts "No gcloud account. Attempting to login from env vars GCLOUD_ACCOUNT_EMAIL and GCLOUD_ACCOUNT_KEY."
gcloud_account_key = Tempfile.new('gcloud-account-key')
gcloud_account_key.write(Runtime::Env.gcloud_account_key)
gcloud_account_key.close
gcloud_account_email = Runtime::Env.gcloud_account_email
shell("gcloud auth activate-service-account #{gcloud_account_email} --key-file #{gcloud_account_key.path}")
ensure
gcloud_account_key && gcloud_account_key.unlink
end
As you can see this function does execute operating system command by using gcloud_account_email
variable which is taken from env.
That function is being called at login_if_not_already_logged_in
function which is located at same file. Finally login_if_not_already_logged_in
is being at within create!
function which looks like being executed during Auto Deploy procedure.
def create!
validate_dependencies
login_if_not_already_logged_in
shell <<~CMD.tr("\n", ' ')
gcloud container clusters
create #{cluster_name}
#{auth_options}
--enable-basic-auth
--zone #{Runtime::Env.gcloud_zone}
&& gcloud container clusters
get-credentials
--zone #{Runtime::Env.gcloud_zone}
#{cluster_name}
CMD
@api_url = `kubectl config view --minify -o jsonpath='{.clusters[].cluster.server}'`
@admin_user = "#{cluster_name}-admin"
master_auth = JSON.parse(`gcloud container clusters describe #{cluster_name} --zone #{Runtime::Env.gcloud_zone} --format 'json(masterAuth.username, masterAuth.password)'`)
shell <<~CMD.tr("\n", ' ')
kubectl config set-credentials #{@admin_user}
--username #{master_auth['masterAuth']['username']}
--password #{master_auth['masterAuth']['password']}
CMD
if rbac
create_service_account
secrets = JSON.parse(`kubectl get secrets -o json`)
gitlab_account = secrets['items'].find do |item|
item['metadata']['annotations']['kubernetes.io/service-account.name'] == 'gitlab-account'
end
@ca_certificate = Base64.decode64(gitlab_account['data']['ca.crt'])
@token = Base64.decode64(gitlab_account['data']['token'])
else
@ca_certificate = Base64.decode64(`kubectl get secrets -o jsonpath="{.items[0].data['ca\\.crt']}"`)
@token = Base64.decode64(`kubectl get secrets -o jsonpath='{.items[0].data.token}'`)
end
self
end
Vulnerability
I believe we have multiple command injection issues.
First and foremost, within attempt_login_with_env_vars
function, there is dangerous command execution without proper parameter passing. Since #{gcloud_account_email}
taken from env variable, which I believe can be controller by user/project owner etc, being used as a part of command that is going to be executed. It's highly possible to manipulate that variable and implant payload.
Second issue is about create!
function. And I believe it's highly possible to exploit it. The problem is about following code section.
master_auth = JSON.parse(`gcloud container clusters describe #{cluster_name} --zone #{Runtime::Env.gcloud_zone} --format 'json(masterAuth.username, masterAuth.password)'`)
shell <<~CMD.tr("\n", ' ')
kubectl config set-credentials #{@admin_user}
--username #{master_auth['masterAuth']['username']}
--password #{master_auth['masterAuth']['password']}
CMD
In here, Gitlab backend system runs gcloud
command in order to retrieve username and password from GCloud and then use username
and password
withing operating system command.
Since it's possible to change that password
to whatever you want by using Google Cloud, you can inject payload withing password field something like QEvN$(ping${IFS}hacker.com)H0qIhN
.
Ofcourse I can't send a PoC video since it's requires a Gcloud account, which requires lots of additional steps at google side. But I believe you can easily spot that issue.
Impact
Successfully exploitation of one of these vulnerability (especially the second one) it's becomes a Remote Code Execution that affects gitlab.com
itself and all the self-hosted installations.
Attachments
Warning: Attachments received through HackerOne, please exercise caution!