企业通常会使用Gitlab作为内部代码管理平台,一来私有仓库更加安全,二来gitlab的功能十分完整。但仍不能保证私有仓库中的代码不被泄露到外部,于是对gitlab的权限审计以及下载审计就变得尤为重要。本文将基于gitlab-ee-11.10版本,详细叙述如何对gitlab的权限及代码下载进行审计。

0×00 快速部署gitlab

笔者使用了docker进行快速部署:

docker pull gitlab/gitlab-ee

docker run --detach --hostname gitlab.example.com --publish 443:443 --publish 80:80 --publish 22:22 --name gitlab --restart always --volume /srv/gitlab/config:/etc/gitlab --volume /srv/gitlab/logs:/var/log/gitlab --volume /srv/gitlab/data:/var/opt/gitlab gitlab/gitlab-ee:latest

gitlab可以与ldap绑定,使用AD域账号进行登录。如果想要修改gitlab.rb文件,可以登入到容器中修改:

docker exec -it CONTAINER_ID /bin/bash

配置完成后,使用root访问http://ip:

0×01 Git的传输协议了解

Git主要以两种方式跨越两个仓库传输数据。

1.哑协议

Git基于HTTP之上传输通常被称为哑协议,这是因为它在服务端不需要有针对Git特有的代码。这个获取过程仅仅是一系列GET请求,客户端可以假定服务端的Git仓库中的布局。简单解读官方给出的举例,一次git clone过程:

git clone http://github.com/schacon/simplegit-progit.git //下载simplegit-progit

Initialized empty Git repository in /private/tmp/simplegit-progit/.git/ //在/private/tmp/simplegit-progit/.git/目录中初始化一个空的git仓库

got ca82a6dff817ec66f44342007202690a93763949 //获取info/refs文件,这个文件由服务端的update-server-info生成,用于给不进行动态包生成的哑服务器提供辅助信息文件,以帮助客户机发现服务器有哪些引用和包,哑服务器意味着通过http访问

walk ca82a6dff817ec66f44342007202690a93763949 //获取commit对象

got 085bb3bcb608e1e8451d4b2432f8ecbe6306e7e7 //查看commit对象的内容

Getting alternates list for http://github.com/schacon/simplegit-progit.git //获取替代仓库list

Getting pack list for http://github.com/schacon/simplegit-progit.git //获取打包文件list

Getting index for pack 816a9b2334da9953e530f27bcac22082a9f5b835 //获取这个打包文件的索引

Getting pack 816a9b2334da9953e530f27bcac22082a9f5b835 which contains cfda3bf379e4f8dba8717dee55aab78aef7f4daf //查看打包文件的索引是否包括要找的对象

walk 085bb3bcb608e1e8451d4b2432f8ecbe6306e7e7 //获取commit

walk a11bef06a3f659402fe7563abf99ad00de2209e6 //下载对象

2.智能协议

HTTP方法是很简单但效率不是很高。使用智能协议是传送数据的更常用的方法。这些协议在远端都有Git智能型进程在服务,它可以读出本地数据并计算出客户端所需要的合适的数据给它,这有两类传输数据的进程:一对用于上传数据和一对用于下载。此处只对下载展开描述:

当下载数据时,fetch-pack和upload-pack进程就起作用了。客户端启动fetch-pack进程,连接至远端的upload-pack进程,以协商后续数据传输过程。在远端仓库有不同的方式启动upload-pack进程。你可以使用与receive-pack(接收推送到存储库中的内容时所启用的进程)相同的透过SSH管道的方式,也可以通过Git后台来启动这个进程,它默认监听在9418号端口上。这里fetch-pack进程在连接后像这样向后发送数据:

fgit-upload-pack schacon/simplegit-progit.git\0host=myserver.com\0

它也是以4字节指定后续字节长度的方式开始,然后是要运行的命令,和一个空字节,然后是服务端的主机名,再跟随一个最后的空字节。Git后台进程会检查这个命令是否可以运行,以及那个仓库是否存在,以及是否具有公开权限。如果所有检查都通过了,它会启动这个upload-pack进程并将客户端的请求移交给它。

如果你透过SSH使用获取功能,fetch-pack会像这样运行:

ssh -x git@github.com "git-upload-pack 'schacon/simplegit-progit.git'"

0×02 gitlab数据库结构了解

docker镜像使用的是postgresql数据库,一共有236张数据表,我们知道gitlab采用了ueba的用户权限管理模型,因此想要获得用户、项目、项目组、key之间的关系,我们首先要关心这几张表:

identities存储ldap的信息,其中extern_uid存储ldap的部门等信息 :

ColumnType id integer extern_uid character varying provider character varying user_id integer created_at timestamp without time zone updated_at timestamp without time zone secondary_extern_uid character varying saml_provider_id integer

keys存储key,以及与user_id的对应关系:

ColumnType id integer user_id integer created_at timestamp without time zone updated_at timestamp without time zone key text title character varying type character varying fingerprint character varying public boolean last_used_at timestamp without time zone

namespaces存储用户及项目组的路径,主要用于获取项目组(type=’Group’)的信息(description)

ColumnType id integer name character varying path character varying owner_id integer created_at timestamp without time zone updated_at timestamp without time zone type character varying description character varying avatar character varying membership_lock boolean share_with_group_lock boolean visibility_level integer request_access_enabled boolean ldap_sync_status character varying ldap_sync_error character varying ldap_sync_last_update_at timestamp without time zone ldap_sync_last_successful_update_at timestamp without time zone ldap_sync_last_sync_at timestamp without time zone description_html text lfs_enabled boolean parent_id integer shared_runners_minutes_limit integer repository_size_limit bigint require_two_factor_authentication boolean two_factor_grace_period integer cached_markdown_version integer plan_id integer project_creation_level integer runners_token character varying trial_ends_on timestamp with time zone file_template_project_id integer saml_discovery_token character varying runners_token_encrypted character varying custom_project_templates_group_id integer auto_devops_enabled boolean extra_shared_runners_minutes_limit integer

project_authorizations存储用户、项目以及访问权限的关系

ColumnType user_id integer project_id integer access_level integer

其中,access_level的含义为:

10 => Guest access

20 => Reporter access

30 => Developer access

40 => Maintainer access

50 => Owner access # Only valid for groups

projects存储项目信息: