### Bitbucket’s Migration Endpoint
The Data Center Migration tool allows *Admins* or *System Admins* to migrate Git repositories from Bitbucket Server to Bitbucket Data Center. To start the migration process the admin has to export the repositories from the Bitbucket Server instance first. During the export process a TAR archive with the following structure is being created.
#### Example TAR archive
```java
_/repository/hierarchy_begin/c3b3efc5cb93609ad4fc
_/repository/hierarchy_end/c3b3efc5cb93609ad4fc
com.atlassian.bitbucket.server.bitbucket-instance-migration_instanceDetails/instance-details.json.atl.gz
com.atlassian.bitbucket.server.bitbucket-instance-migration_metadata/project_68/project.json.atl.gz
com.atlassian.bitbucket.server.bitbucket-instance-migration_metadata/project_68/repository_59.json.atl.gz
com.atlassian.bitbucket.server.bitbucket-instance-migration_permissions/project/68/all-permissions.json.atl.gz
com.atlassian.bitbucket.server.bitbucket-instance-migration_permissions/project/68/permissions.json.atl.gz
com.atlassian.bitbucket.server.bitbucket-instance-migration_permissions/repository/59/permissions.json.atl.gz
com.atlassian.bitbucket.server.bitbucket-git_git/repositories/59/hooks/hooks.atl.tar.atl.gz
com.atlassian.bitbucket.server.bitbucket-git_git/repositories/59/contents/objects.atl.tar
com.atlassian.bitbucket.server.bitbucket-git_git/repositories/59/metadata/metadata.atl.tar.atl.gz
com.atlassian.bitbucket.server.bitbucket-git-lfs_gitLfsSettings/59/git-lfs-settings.json.atl.gz
```
As we can see, the exported TAR archive contains multiple GZIP and TAR compressed files. Especially the file `hooks.atl.tar.atl.gz` looks suspicious since it contains Git hooks which are scripts that are executed every time a paticular event occurs in a Git repository. Manipulating such a TAR archive entry with the `../../` notation and starting the import process leads to a Remote Code Execution vulnerability as described in the next section.
### Insecure Archive extraction
During the import process of a repository the Git hooks from the file `hooks.atl.tar.atl.gz` are stored in the directory `${BITBUCKET_DATA}/shared/data/repositories/${REPO_ID}/imported-hooks/`and are therefore ignored from being executed since the regular hooks of a repository are stored in the directory `${BITBUCKET_DATA}/shared/data/repositories/${REPO_ID}/hooks/`. However, if an attacker controls the contents of the file `hooks.atl.tar.atl.gz` it is possible to traverse out of the intended directory and drop a hook in an arbitrary directory. This is caused by insecure extraction of the GZip compressed TAR file.
The following code snippet shows the simplified function `extractToDisk` which takes the path to the file `hooks.atl.tar.atl.gz` as parameter target. Then the function `read` is called with the lambda expression in line 4-9. This lambda expression implements the function `accept` of the interface `IoConsumer<T>`.
#### Listing 1: Insecure Extraction of Archives
```java
public void extractToDisk(@Nonnull Path target, @Nonnull Predicate<String> filter) throws IOException {
⋮
this.read((entrySource) -> {
Path entryPath = entrySource.getPath();
String filename = entryPath.getFileName().toString();
⋮
entrySource.extractToDisk(target.resolve(entryPath));
}, filter);
}
```
The following code snippet shows the function declaration of the function `read`. This function iterates over all archive entries and calls the function `accept` on an object of the class `TarEntrySource` containing the user input. We can see that the unsanitized user input from the source `org.apache.commons.compress.archivers.tar.TarArchiveEntry.getName()` (Listing 2, line 7) reaches the sensitive sink `java.nio.Paths.get()` (Listing 2, line 9) indicating a Path Traversal vulnerability.
Since the function `accept` is implemented by the above defined lambda expression, we can track the user input to the to the function call of `TarEntrySource.extractToDisk()` (Listing 1 line 7).
#### Listing 2: Reading the TAR archive
```java
public void read(@Nonnull IoConsumer<EntrySource> reader,
@Nonnull Predicate<String> filter) throws IOException {
⋮
TarArchiveEntry entry;
while ((entry = (TarArchiveEntry) inputStream.getNextEntry()) != null) {
InputStream entryInputStream = new CloseShieldInputStream(inputStream);
String name = entry.getName();
if (filter.test(name)) {
reader.accept(new TarEntrySource(entryInputStream, Paths.get(name), entry));
}
}
}
```
The following Listing shows the function `extractToDisk` of the class `TarEntrySource` which takes the unsanitized path as function parameter. We can see that all sub directories of the path are created (Listing 3, line 5) and the file is copied into that directory (Listing 3, line 8).
#### Listing 3: Dropping the File
```java
private static class TarEntrySource extends DefaultEntrySource {
⋮
public void extractToDisk(@Nonnull Path target) throws IOException {
⋮
Files.createDirectories(target.getParent());
OutputStream out = new FileOutputStream(target.toFile());
⋮
IoUtils.copy(this.inputStream, out, 32768);
⋮
PosixFileAttributeView fileAttributeView = (PosixFileAttributeView)Files.getFileAttributeView(target, PosixFileAttributeView.class);
fileAttributeView.setPermissions(FilePermissionUtils.toPosixFilePermissions(this.tarArchiveEntry.getMode()));
}
}
```
This path traversal vulnerability enables an attacker to drop a Git hook in an attacker controlled Bitbucket repository. However, if the file permissisons of the shell script are not set properly e.g. the execute bit is not set the Git hook is not being executed. Interesting to mention is that a TAR archive contains meta information of a file entry like the modification date, the user name, the group name and the file mode (file permissions). In line 11 of Listing 3 the file permissions are set to the corresponding permissions of the archive entry.
## Timeline
| Date | What |
| ---------- | ------------------------------------------------------------ |
| 2019/02/27 | Reported the Path Traversal vulnerability to Atlassian. |
| 2019/03/11 | Atlassian confirmed the vulnerability and assigned issue BSERV-11706. |
| 2019/04/01 | Atlassian fixed the issue in Bitbucket 6.1.2. |
| 2019/05/22 | Atlassian published a [security advisory](https://confluence.atlassian.com/bitbucketserver/bitbucket-server-security-advisory-2019-05-22-969526871.html) for Bitbucket. |
暂无评论