Pentesting Git source repositories

Guillaume Quéré


Attack the source, Luke

During a pentest you sometimes may stumble accross public projects hosted on a git web service. The most commonly found in enterprise environments are BitBucket and GitLab.

You can check these URLs to see if they host any public projects:

From there you may want to dump all public projects to see if there are secrets stored in them:

Patterns of secrets to look for

From experience, these regular expressions have a high chance of finding cleartext secrets:

://[a-zA-Z0-9_-]\+:[^/@]\+@     // passwords in URLs
curl .*-u 
wget .*--password
wget .*--http-password
wget .*--ftp-password
wget .*--proxy-password
echo .*|\s*passwd
echo .*|\s*chpasswd
Authorization.*:.*Basic
Authorization.*:.*Bearer
docker login .*-p 
<password>[^<]\+</password>
mysql .*-p
mysql .*--password
PGPASSWORD                      // environment variable to set the psql password on the commandline
RSYNC_PASSWORD                  // environment variable to set the rsync password on the commandline
BEGIN .*PRIVATE
[^a-zA-Z0-9]7z[ zr].*-p[^ ]     // password protected 7z files
unzip .*-P                      // password protected zip files
mount .*-o.*password=           // CIFS share mounted with a username/password
jfrog .*--password=
jfrog .*--apiKey=
mongo .*-p 
cqlsh .*-p 
ldapsearch .*-w 
ldapsearch .*-y 
X-Vault-Token
vault login 
VAULT_TOKEN
secret_id
hvs\.                                     // Vault token, new format
erlang.cookie
[^a-zA-Z0-9]11[0-9a-f]\{32\}[^a-zA-Z0-9]  // Jenkins tokens
jnlpUrl .* -secret                        // Jenkins agent
[^a-zA-Z0-9]eyJhbGc                       // JWT
[^a-zA-Z0-9]AKCp5                         // Artifactory API token

Copy and paste regexp:

ngp -re '://[a-zA-Z0-9_-]\+:[^/@]\+@\|curl .*-u \|curl .*--user \|wget .*--password\|wget .*--http-password\|wget .*--ftp-password\|wget .*--proxy-password\|echo .*|\s*passwd\|echo .*|\s*chpasswd\|Authorization.*:.*Basic\|Authorization.*:.*Bearer\|docker login .*-p \|docker login .*--password \|<<password>[^<]\+</password>\|mysql .*-p\|mysql .*--password\|PGPASSWORD\|RSYNC_PASSWORD\|BEGIN .*PRIVATE\|[^a-zA-Z0-9]7z[ zr].*-p[^ ]\|unzip .*-P\|mount .*-o.*password=\|jfrog .*--password=\|jfrog .*--apiKey=\|mongo .*-p\|cqlsh .*-p\|ldapsearch .*-w\|ldapsearch .*-y\|sshpass\|X-Vault-Token\|secret_id\|VAULT_TOKEN\|vault login\|erlang.cookie\|secret_id\|[^a-zA-Z0-9]11[0-9a-f]\{32\}[^a-zA-Z0-9]\|jnlpUrl .* -secret \|hvs\.\|eyJhbGc\|AKCp5'

Please submit your own favourites :)

Do not use grep

Grep is really not recommended once you’re working several hundreds of megabytes or even gigabytes of data, as you’ll oftentimes find yourself re-running the same commands over and over, adding multiple pipes and pagers along the way. This is a cumbersome process for which I’ve developed a solution: instead of using grep I’ve been using ngp for years now.

This ncurses tool lets you browse search results in a terminal, execute subsearches on the initial results and open results directly in vim. Try it out the next time you’re auditing code!

Files containing secrets

These files usually contain secrets:

*id_rsa
*.key
*.ppk
*.secure
.pgpass
.davfs2/secrets

Git history

Git is complex and a lot of people don’t know how to properly rebase to hide deleted secrets.

You can recover secrets lost in the repo’s history with these projects:

BitBucket vulnerabilities

BitBucket has an interesting feature for use in redteam engagements: any admin can add a public key to a user. You can use this to commit as another user.

BitBucket version is found in the HTML footer.

CVE-2019-15000: Arbitrary file read

Applicable to:

CVE-2019-15000 PoC here.

CVE-2022-36804: Unauthenticated RCE

Advisory and exploit

Gitlab vulnerabilities

Note that you need to be authenticated to read the version. It’s located at this endpoint: https://gitlab.example.com/api/v4/version.

CVE-2020-10977: Arbitrary file read into RCE < 12.9.1

Requires bug creation and move rights.

CVE-2020-10977 PoC here.